Contravariance
- TypeScript course
- Advanced
- Lesson 14/57
- 4 min
Learn the contravariance rule for parameters.
What is contravariance?
Contravariance is the rule where the subtype relationship is preserved in the opposite direction. If Dog is a subtype of Animal, a function (p: Animal) => void is treated as a subtype of (p: Dog) => void. Because a function accepting Animal can accept any Dog. This rule applies to parameter types when strictFunctionTypes is on.
class Animal {}
class Dog extends Animal {}
const handleAnimal = (a: Animal) => console.log(a);
const handleDog: (d: Dog) => void = handleAnimal; // valid under strictFunctionTypesWhy contravariance is safe
Contravariance is logically safe: where (p: Dog) => void is expected, the real function accepts the wider Animal type, so no Dog call can fail. Doing the reverse means the function may use Dog-specific members while being called with a Cat; that direction is unsafe and rejected under strictFunctionTypes.
class Animal {}
class Cat extends Animal { meow() {} }
class Dog extends Animal { bark() {} }
const bad: (a: Animal) => void = (d: Dog) => d.bark(); // errorPractice Demonstrate contravariant assignment
Define a Dog class extending Animal. Write a function of type (a: Animal) => void and assign it to a variable of type (d: Dog) => void. Then call that variable with new Dog().
Starter code
class Animal {
name = "animal";
}
// Dog sınıfını Animal'dan türet
// Animal kabul eden fonksiyonu yaz
// Fonksiyonu (d: Dog) => void türüne ata ve bir Dog ile çağırSample solution
class Animal {
name = "animal";
}
class Dog extends Animal {}
const logAnimal = (a: Animal) => console.log(a.name);
const logDog: (d: Dog) => void = logAnimal;
logDog(new Dog());Expected output
animal
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which assignment is valid when strictFunctionTypes is on?
- const f: (a: Animal) => void = (d: Dog) => console.log(d);
- const f: Dog = new Animal();
- const f: () => Dog = () => new Animal();
- const f: (d: Dog) => void = (a: Animal) => console.log(a); Correct answer
Explanation: Parameters are contravariant; a function accepting Animal can be assigned where a Dog parameter is expected.
2 Contravariant assignment
class Animal {}
class Dog extends Animal {}
const logAnimal = (a: Animal) => console.log("animal");
const handler: (d: Dog) => void = ____;
class Animal {}
class Dog extends Animal {}
const logAnimal = (a: Animal) => console.log("animal");
const handler: (d: Dog) => void = logAnimal;
Explanation: logAnimal accepts Animal; via contravariance it is safely assignable to a (d: Dog) => void expectation.
3 Contravariance parts
| Term | Meaning |
|---|---|
Dog alt tür, Animal üst tür |
subtype relation toward supertype |
(p: Animal) => void |
subtype of (p: Dog) => void |
strictFunctionTypes |
enforces parameter contravariance |
Parametre türü |
Contravariance area |