Variance error not caught by the type system
jyuhuan opened this issue · 3 comments
TypeScript Version: 2.1.1
Code
interface Comparator<T> {
compare(x: T, y: T): number
}
class Animal {
getAge(): number { return 10; }
}
class Cat extends Animal {
getClawLength(): number { return 20; }
}
class AnimalComparator implements Comparator<Animal> {
compare(x: Animal, y: Animal): number {
return x.getAge() - y.getAge();
}
}
class CatComparator implements Comparator<Cat> {
compare(x: Cat, y: Cat): number {
return x.getClawLength() - y.getClawLength();
}
}
function sortAnimals(animals: Animal[], comparator: Comparator<Animal>): void {
// Irrelevant code ...
comparator.compare(animals[0], animals[1]);
// Irrelevant code ...
}
const animals = [ new Animal(), new Animal(), new Animal() ]
sortAnimals(animals, new CatComparator())Expected behavior:
A type error containing the following message should be reported by the compiler:
Type 'Comparator<Cat>' is not assignable to type 'Comparator<Animal>'
Actual behavior:
A successful compilation. Then, at runtime, a type error is thrown at the compare function of CatCompare:
TypeError: x.getClawLength is not a function
Discussion:
Although the compiler of TypeScript is able to catch a similar error as follows:
const cats: Cat[] = [ new Animal(), new Animal() ];
^ Type 'Animal[]' is not assignable to type 'Cat[]'.However, it seems that the compiler only makes sure that the built-in Array type is invariant. For other generic types, variance is not checked.
See #1394
@RyanCavanaugh Thanks for linking that issue to this one. I would like to point out that this issue is less of a request for variance annotation syntax. The focus here is a type error that is missed by the the compiler, which indicates that the type inference system of TypeScript may not be sound.
It's definitely not sound. You may want to read https://github.com/Microsoft/TypeScript/wiki/FAQ#why-are-function-parameters-bivariant