Flow: Specify a range number

Created on 18 May 2017  路  8Comments  路  Source: facebook/flow

If I want to specify a variable to be a number type with a range, how can I do that?

For example, I have float variables r/g/b for colors within 0..1 ranges.

type ColorChannelType = ...  // a number type within 0 to 1 range

const r: ColorChannelType = 0.3  // good
const g: ColorChannelType = 0.2  // good
const b: ColorChannelType = 0.1  // good

const rx: ColorChannelType = 3   // should raise an error
feature request

Most helpful comment

I think it would be useful to restrict numeric types in various ways:

  • Closed intervals (ranges)
  • Integer (pseudo-type which allows only exact integers (forces you to use floor/ceil when operands aren't integers)
  • Satisfies some arbitrary test: {x| x % 2 === 1}

All 8 comments

You can't do that at the moment. To be honest, this doesn't seem particularly useful.

I think it would be useful to restrict numeric types in various ways:

  • Closed intervals (ranges)
  • Integer (pseudo-type which allows only exact integers (forces you to use floor/ceil when operands aren't integers)
  • Satisfies some arbitrary test: {x| x % 2 === 1}

While writing reactive-material I wanted to specify statically that a prop only accepts a range of integers from 1 to 24. Eventually wrote a full union type but it felt wrong. Something like Integer & 1..24 could have been really useful.

It's not particularly hard to implement this feature. 1..5 could be basically sugar for 1 | 2 | 3 | 4 | 5. The problem is that if Flow adds this, people would want proper refinements for this.

This should work, right?

function test(x: number):1..5 {
  if (Number.isInteger(x) && x >= 1 && x <= 5) {
    return x;
 }

  return 1;
}

How about this?

function test(x: 1..3):1..5 {
  return x + 1;
}

This would be much harder to implement.

Interesting case. but if Flow knows to validate

function test(x: number): number {
  return x + 1;
}

and able to infer the two sides of the arithmetic operation (x : 1..5, 1) isn't it a scoped problem?

Definitely would want the basic refinement with relational operators. For other cases, I would be satisfied with simply having to clamp an expression with Math.min() and Math.max().

So your second example:

function test(x: number): 1..5 {
  return clamp(1, 5, x + 1);
}

function clamp(lower, upper, value) {
  return Math.max(lower, Math.min(upper, value));
}

What I'd be interested in is how to specify the type of clamp in this case.

I don't feel comfortable with idea of applying Math.max and Math.min for simple add. Can't it be reached statically? Maybe we can restrict arithmetic operations on ranges to ranges and number literals

Is there something done about this here?

Was this page helpful?
0 / 5 - 0 ratings