Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Defining a Union Type from object values in Flow

I have an enum like this:

const Filter = {
  ALL: 'ALL',
  COMPLETED: 'COMPLETED',
  UNCOMPLETED: 'UNCOMPLETED'
};

What I'd like to do is declare a union type like this:

type FilterType = Filter.ALL | Filter.COMPLETED | Filter.UNCOMPLETED

However, this fails, but I'm not sure why. According to the Flow docs:

When you create an object with its properties, you create a sealed object type in Flow. These sealed objects will know all of the properties you declared them with and the types of their values.

So, if I'm reading that correctly, Flow should be able to create a type from those values. Instead, it fails with:

Cannot use string as a type because string is a value. To get the type of a value use typeof.

Here's a link to a Flow Try with a possible solution (that I'm not happy with) and other approaches that have unsuccessfully worked.

like image 429
bbstilson Avatar asked Jul 03 '18 21:07

bbstilson


1 Answers

There's an easier solution. You can use $Values utility to get union of value types. And in order to make flow resolve types as literal types instead of just string the object should be frozen:

const FilterA = Object.freeze({
  ALL: 'ALL',
  COMPLETED: 'COMPLETED',
  UNCOMPLETED: 'UNCOMPLETED'
});

type FilterTypeA = $Values<typeof FilterA>;


let a: FilterTypeA = FilterA.ALL; //OK
a = 'COMPLETED'; //OK

a = 'foo'; //$Expect error: string is incompatible with enum FilterTypeA

Try

This pattern works since 0.60.0 version

like image 184
Aleksey L. Avatar answered Oct 15 '22 14:10

Aleksey L.