0
0
Typescriptprogramming~7 mins

Generic type variance in Typescript

Choose your learning style9 modes available
Introduction

Generic type variance helps control how types relate when used with generics. It makes your code safer and more flexible by defining if types can be replaced by their subtypes or supertypes.

When you want to allow a function to accept a generic type or its subtypes safely.
When you design reusable components that work with different but related types.
When you want to prevent errors by restricting how generic types can be substituted.
When working with collections like arrays or lists that hold generic types.
When defining APIs that should accept or return types in a controlled way.
Syntax
Typescript
// TypeScript does not support 'in' or 'out' keywords like some languages
// Covariance is expressed with readonly properties
// Contravariance is expressed with function parameter types

TypeScript does not use explicit 'in' or 'out' keywords like some languages.

Covariance often happens with readonly properties, contravariance with function parameters.

Examples
This shows covariance: you can use a subtype where a supertype is expected.
Typescript
interface ReadonlyArray<T> {
  readonly [index: number]: T;
}
Function parameters are contravariant, meaning you can use a supertype where a subtype is expected.
Typescript
type Handler<T> = (arg: T) => void;
// Function parameters are contravariant in TypeScript
Covariance allows passing ReadonlyArray<Dog> where ReadonlyArray<Animal> is expected.
Typescript
function processAnimals(animals: ReadonlyArray<Animal>) {}

const dogs: ReadonlyArray<Dog> = [{ name: 'Buddy' }];
processAnimals(dogs);
Sample Program

This example shows covariance: a ReadonlyArray<Dog> can be passed to a function expecting ReadonlyArray<Animal> safely.

Typescript
class Animal {
  name: string;
  constructor(name: string) {
    this.name = name;
  }
}

class Dog extends Animal {
  bark() {
    console.log(`${this.name} says Woof!`);
  }
}

function feedAnimals(animals: ReadonlyArray<Animal>) {
  animals.forEach(animal => console.log(`Feeding ${animal.name}`));
}

const dogs: ReadonlyArray<Dog> = [new Dog('Buddy'), new Dog('Max')];
feedAnimals(dogs);
OutputSuccess
Important Notes

Covariance means you can use a more specific type where a more general type is expected.

Contravariance means you can use a more general type where a more specific type is expected.

TypeScript infers variance mostly from how types are used (e.g., readonly properties for covariance).

Summary

Generic type variance controls how generic types relate to each other.

Covariance allows substituting a subtype for a supertype safely.

Contravariance allows substituting a supertype for a subtype safely.