CodeBlanks Logo Icon CodeBlanks

Contravariance

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 strictFunctionTypes

Why 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();  // error

Practice 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

index.ts
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ğır

Sample solution

index.ts
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

Question
class Animal {}
class Dog extends Animal {}

const logAnimal = (a: Animal) => console.log("animal");

const handler: (d: Dog) => void = ____;
Answer
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

All lessons in Advanced