I have a method that might return either a Map or a Vector, and since both types implement KeyedIterable
— Vector<T>
specifically implementing KeyedIterable<int, T>
— I figured I could cover both cases with a KeyedIterable<arraykey, T>
return type. However, even though arraykey
is a more general type than int
, this doesn't work. For example, the typechecker complains on the following code:
<?hh // strict
class A {
public static function foo(): KeyedIterable<arraykey, mixed> {
return Vector{};
/*
Invalid return type (Typing[4110])
This is an array key (int/string)
It is incompatible with an int
Considering that this type argument is invariant with respect to KeyedIterable
*/
}
}
Why can't I do this?
This is because KeyedIterable
isn't read-only, so can't take a subtype.
For instance, A::foo()->toMap()
will have the type Map<arraykey, mixed>
from the type signatures, but the actual type Map<int, mixed>
.