CodeBlanks Logo Icon CodeBlanks

Covariance

Learn the covariance rule for functions.

What is covariance?

Covariance is the rule where the subtype relationship is preserved in the same direction. If Dog is a subtype of Animal, then () => Dog is treated as a subtype of () => Animal. You can assign a function returning Dog where a function returning Animal is expected.

class Animal { name = "animal"; }
class Dog extends Animal { bark() {} }

type AnimalMaker = () => Animal;
const makeDog: () => Dog = () => new Dog();
const maker: AnimalMaker = makeDog;  // valid

Covariance in arrays

Arrays are covariant too: Dog[] is treated as a subtype of Animal[]. This follows from every element satisfying the Animal interface. The looseness also permits some unsound operations; for instance, assigning Dog[] where Animal[] is expected and then pushing another subtype into that array may not error at compile time.

const dogs: Dog[] = [new Dog(), new Dog()];
const animals: Animal[] = dogs;  // valid: covariant

Practice Demonstrate covariant function assignment

Define a Dog class extending Animal. Assign a () => Dog function to a () => Animal typed variable, and print the name property of the returned animal via console.log.

Starter code

index.ts
class Animal {
  name = "animal";
}

// Dog sınıfını Animal'dan türet

// köpek üreten fonksiyonu tanımla

// covariant atama yapıp sonucu yazdır

Sample solution

index.ts
class Animal {
  name = "animal";
}

class Dog extends Animal {}

const makeDog: () => Dog = () => new Dog();
const makeAnimal: () => Animal = makeDog;

const a = makeAnimal();
console.log(a.name);

Expected output

animal

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Which of the following assignments is valid due to covariance?

  • const a: Dog = new Animal();
  • const a: () => Animal = () => new Dog(); Correct answer
  • const a: () => Dog = () => new Animal();
  • const a: Dog[] = [new Animal()];

Explanation: Covariance works in the same direction for return types; a function returning Dog is assignable where Animal is expected.

2 Covariant return type

Question
class Animal {}
class Cat extends Animal {}

const makeCat: () => Cat = () => new Cat();
const makeAnimal: () => Animal = ____;
Answer
class Animal {}
class Cat extends Animal {}

const makeCat: () => Cat = () => new Cat();
const makeAnimal: () => Animal = makeCat;

Explanation: makeCat returns Cat and Cat is an Animal, so via covariance it is assignable to a () => Animal expectation.

3 Covariance parts

Term Meaning
Dog alt tür, Animal üst tür subtype relation
() => Dog assignable to Animal-returning expectation
Dog[] counted as subtype of Animal[]
Dönüş türü Covariance area

All lessons in Advanced