Reputation: 105
I'm trying to understand why flow is complaining about incompatibility between the properties of two very similar objects (try-flow-example):
/* @flow */
type Cow = {
name: ?string
}
type NamedCow = {
name: string
}
function foo (c: Cow): string {
if (c.name == null) return 'anonymous'
return c.name
}
const elsa: NamedCow = { name: 'Elsa' }
foo(elsa)
Flow gives the following error with the above code:
17: foo(elsa)
^ NamedCow. This type is incompatible with the expected param type of
10: function foo (c: Cow): string {
^ Cow
Property `name` is incompatible:
7: name: string
^ string. This type is incompatible with
3: name: ?string
^ null or undefined
Why is the more specific name: string
incompatible with the less specific name: ?string
? Wouldn't NamedCow
be covariant to Cow
over the name property since the name property of NamedCow
is a sub-set of the name property of Cow?
Relevant docs: Flow docs on subtypes
Upvotes: 1
Views: 201
Reputation: 160397
Object types are invariant. This is due to the fact that object properties can be read and written.
To see why covariance is unsafe, consider a function that assigns null
to the property name
in the foo
function.
Passing a Cow
type: assignment to name = null
poses no issue since name
can be ?string
.
But, if you pass a NamedCow
type, the assignment to name = null
would violate the type for name
which is only string
.
You can annotate name
to be covariant by prefixing it with +
, that is +name: ?string
. This indicates that no writes will be performed on it. That should clear away the errors you're currently seeing. (The property variance modifiers are somewhat hidden in the docs)
Upvotes: 2