Reputation: 613
What is the typing relationship between type A
& type B
?
type A = {
a: string,
}
type B = {
a: string,
b?: string, // Same thing as —> "b: void | string"
}
// "-" means contravariant & write only & can accept supertypes
function test<-T: B>(value: T): void {}
declare var foo: A
test(foo)
According to https://flowtype.org/docs/variance.html#object-types....
...the subtyping relationship between objects is derived from the subtyping relationships of their properties.
Since b?: string
is the same thing as b: void | string
, does that mean we are comparing two distinct value types (with different properties) with no relationship?
It seems logical to me that { a: string }
would be a "supertype" of { a: string, b: string }
, since it is a more specific "value type." ...the same thing would go for { a: string }
and { a: string, b?: string }
.
Upvotes: 2
Views: 350
Reputation: 58885
What is the typing relationship between type A & type B?
B
is a subtype of A
.
You can verify this by typchecking code like this:
let b: B = {a:'bar', b:'wibble' };
let a: A = b;
// "-" means contravariant & write only & can accept supertypes function test<-T: B>(value: T): void {}
I think this might be where you are getting confused.
You can't read from a contravariant value, which means it doesn't make very much sense as the argument to a function. And this isn't just an arbitrary restriction: if you could use the value, you wouldn't be able to do anything with it because you couldn't make any assumptions about what it is.
When we talk about covariant types, we are usually talking about function arguments. The function which uses that argument can usually just ignore any specialization and therefore deal with any subtype. We specify the variance from the perspective of a value consumer, and we're expressing which providers are compatible.
A contravariant type is usually a return value. We specify a contravariant return type from the perspective of a provider. The supertype restriction comes in by saying that any consumer of this value must not expect something more specific that we're giving it. For example, specifying a contravariant return type of Dog
means that I'm going to give you some kind of Dog
, but you may not assume anything more than that: you can treat it like a Mammal
or a HasFur
, but you can't treat it like a Poodle
or else you're going to have problems, which is what the typechecker prevents here.
Upvotes: 2