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, which 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 would be accepted).
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
This will work, but it will be not resistant for the annotation changes 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 an error that is not easy to track.
One more downside of this approach, that is not easy to spot, is that spreading inexact type will make all its parameter be optional, what is not obvious if one doesn’t know that:
2) Add all shared properties annotation in
NewProperties one by one using
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
length properties as required ones.
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
length properties as mandatory ones.
I have created the eslint rule, that helps to enforce the third option across the project (check for the rule
spread-exact-type in the
eslint-plugin-flowtype set of rules – https://github.com/gajus/eslint-plugin-flowtype#eslint-plugin-flowtype-rules-spread-exact-type). Unfortunately, there is no easy way to detect is the original type exact at the moment when it is created, but this rule allows to check, that
$Exact utility type is added whenever spreading occurs.
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).