|
|
|
|
|
by globuous
1156 days ago
|
|
Yeah, there are some weird stuff in typescript, for instance, this typechecks class Animal {}
class Dog extends Animal {
woof() {}
}
class Cat extends Animal {
meow() {}
}
let append_animals = (animals: Animal[], animal: Animal) => animals.push(animal)
let dogs = [new Dog()]
append_animals(dogs, new Cat())
dogs.map(dog => dog.woof())
Which if you evaluate, you'll obviously get: Uncaught TypeError: dog.woof is not a function
Whereas Mypy won't typecheck the equivalent Python code: class Animal:
pass
class Dog(Animal):
pass
def append_animals(animals: List[Animal], animal: Animal) -> None:
animals.append(animal)
dogs = [Dog()]
append_animals(dogs, Dog())
It'll throw with: $ mypy types.py
types.py:16: error: Argument 1 to "append_animals" has incompatible type "List[Dog]"; expected "List[Animal]"
types.py:16: note: "List" is invariant -- see https://mypy.readthedocs.io/en/stable/common_issues.html#variance
types.py:16: note: Consider using "Sequence" instead, which is covariant
|
|
To expand: TS treats `Dog[]` as a subtype of `Animal[]` because `Dog` is a subtype of `Animal`... that work if you only read values from the array... but trying to change the array, you run into trouble. Some languages let you declare covariance (reading ) and contravariance explicitly to address this issue. To my limited knowledge of TS, that's not possible in TS (as it tries to keep things simple and compatible with JS, probably).
The answers in this[1] SO question explain these concepts better than I could.
[1] https://stackoverflow.com/questions/27414991/contravariance-...