Flow: Intersection Types with Object Spread Behave Inconsistently

Created on 2 Sep 2017  路  3Comments  路  Source: facebook/flow

When creating an intersection of two types, and spreading the "rest props" of that object value, flow does not track the properties with in the spread object properly.

However, if I merge the two types that I was creating an intersection with, the behavior is correct. The documentation implies that an intersection type should provide the intended typing, so this may be a bug with [email protected]?

This try flow demonstrates the issue.

EDIT: I should also note, this does not error on 0.53 or 0.53.1 and could be related to the Made rest parameters in object destructuring patterns sealed, and exact if possible update in 0.54?

spread unionintersections bug

Most helpful comment

Spread without exact object types won't work either as props from your example will have a type of mixed | Array<number>.

Flow can only track rested properties with exact object types.

Also, you can't intersect exact types. Semantically, this would yield an empty type.

Cannot get props.values because property values is missing in props.

But, you can spread your exact object types together in an exact object type:

type A = {|
  firstName: string,
|};

type B = {|
  lastName: string,
|};

type C = {|
  ...A,
  ...B
|};

function test({ firstName, ...props }: C): B {
  return props; // type of props is B
}

Your fixed example.

All 3 comments

It seems to take only the left-most type into account, so when take for instance this example:

type Foo ={ a: number }
type Bar ={ b: number }
type Baz ={ c: number }

type Intersection = Foo & Bar & Baz;
let x:Intersection = {a: 1, b: 2, c: 3};

// error on this line because it assumes spreading x will only result in the property "a"
let y:Intersection = {...x};

If you reorder the type definition to Bar & Foo & Baz it'll think spreading x will result in the property b

Spread without exact object types won't work either as props from your example will have a type of mixed | Array<number>.

Flow can only track rested properties with exact object types.

Also, you can't intersect exact types. Semantically, this would yield an empty type.

Cannot get props.values because property values is missing in props.

But, you can spread your exact object types together in an exact object type:

type A = {|
  firstName: string,
|};

type B = {|
  lastName: string,
|};

type C = {|
  ...A,
  ...B
|};

function test({ firstName, ...props }: C): B {
  return props; // type of props is B
}

Your fixed example.

This behaviour seems to have changed in more recent versions of flow (I'm using 0.68.0 now). If I test my given example again it correctly shows the type of Intersection to be {a: number, b: number, c:number}

Was this page helpful?
0 / 5 - 0 ratings