Inexact vs exact flow object types: spreading

If one wants to add flow annotation to object type and reuse some of the types, that was annotated in another object type, it can be done like:

However, in this case, not all will run smoothly here, as if to check age will accept, not only number type as valid but other as well.

If to annotate objects, as it is done above the age type will become mixed. This has happened because SharedProperties has been annotated as an inexact object, what means, that if it doesn’t explicitly have age property type, it still can have this property, but is not defined in the annotation of the object:

There are a few ways how to annotate NewProperties to obtain the expected type (means only age that has number type should be accepted).

1) Spread SharedProperties type first and then add the annotation to age. In this case, even though age was defined as mixed (no explicitly) in the SharedProperties, its type will be redefined by further age annotation.

This will work, but it will be not resistant for the changes annotation as if for some reason someone will in the future change the order of destructuring SharedProperties and other properties definition, an error will appear one more time, and it will be not easy to track error.

2) Add all shared properties annotation in NewProperties one by one using $PropertyType.

Con of this approach is the case when SharedProperties contains a lot of properties. Then manually adding every prop in the NewProperties definition will diminish most of the pros that we have from having properties types defined in the SharedProperties in the first place. However, if we would want to obtain annotation only from some props from SharedProperties (not all) this method will allow us to do this. Note also, that in this case NewProperties has both name and length properties as required ones.

3) Change SharedProperties to be Exact type. Semantically there are two ways how to make Object annotation to be the exact type (there is no difference between them).


Then our case will look like:

From my perspective, this solution has the most benefits, as it keeps all the pros that destructuring of the SharedProperties is bringing in the first places, at the same time it is more resistant to the order in which destructuring and other properties are added in the NewProperties annotation. Similarly to the previous approach, in this case, both name and length properties as mandatory ones.

Recently my general logic with flow types is that everything should be annotated as exact as possible, if something is annotated not exact, this should be done with the reason under it. Flow maintainers themselves are identifying that migration for Object type to be exact by default is in their roadmap (check this post for more details https://medium.com/flow-type/on-the-roadmap-exact-objects-by-default-16b72933c5cf).

If you have found a spelling error, please, notify us by selecting that text and pressing Ctrl+Enter.

Olena Sovyn
Front-end developer (London, UK). I ❤ React, Redux, lodash, React Storybook, and functional programming overall. Always open to learn something new

Leave a Reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Spelling error report

The following text will be sent to our editors: