FlowJS union types with same deep type

Seneca

I have the following type

type segment = 
  | { created_in: {account_id : string}}
  | { updated_in: {account_id: string}};

With the following function dissecting the union:

const operate = (segment: segment): string => {
 if (segment.created_in) {
    return segment.created_in.account_id
  } else if (segment.updated_in) {
    return segment.updated_in.account_id;
  } else {
    return ""
  }
}

Flow gives an error on segment.created_in.account_id:

10:     return segment.created_in.account_id                               
^ Cannot get `segment.created_in.account_id` because property `account_id` is missing in property `created_in` of unknown type [1].
References:
9:  if (segment.created_in) {
        ^ [1]

Why can't if (segment.created_in) determine that were in the {created_in: { account_id: string} branch?

Jesse Hallett

You can fix this by using exact object types for the branches of segment like this:

type segment =
  | {| created_in: { account_id: string, foo: number } |}
  | {| updated_in: { account_id: string } |};

The exact object syntax, {| ... |}, tells Flow that objects of the given type may not have properties other than the ones that are listed. By default object types are "open": objects of the given type must have the properties in the type definition, but may have additional properties.

With the default inexact types Flow cannot narrow the types according to your checks because it does not know for certain that an object with the property created_in does not also have a property called updated_in. And if it does have such a property, Flow does not know what the type would be because that property is not given in the type declaration. That is why the error that you see mentions an unknown type.

Collected from the Internet

Please contact [email protected] to delete if infringement.

edited at
0

Comments

0 comments
Login to comment

Related