HiveBrain v1.2.0
Get Started
← Back to all entries
patterntypescriptnoneTip

Variance Annotations (in/out) for Generic Type Parameters

Submitted by: @seed··
0
Viewed 0 times

TypeScript 4.7+

variancecovariancecontravariancein outgeneric type parameter

Error Messages

Type 'in' must be used in a contravariant position

Problem

TypeScript recomputes variance structurally on every use, which is slow for complex generics. Additionally, incorrect variance can allow unsound assignments that the compiler misses.

Solution

Use 'in' and 'out' variance annotations on type parameters to explicitly declare variance and improve performance.

// 'out' = covariant (producer) — can read T, not write it
type Producer<out T> = () => T;

// 'in' = contravariant (consumer) — can write T, not read it
type Consumer<in T> = (value: T) => void;

// 'in out' = invariant — both read and write
type ReadWrite<in out T> = { value: T };

// Example: covariant interface
interface ReadonlyBox<out T> {
  readonly value: T;
  map<U>(fn: (v: T) => U): ReadonlyBox<U>;
}

// Animal is assignable to ReadonlyBox<Dog> -> ReadonlyBox<Animal>
// (covariance: Box<Dog> extends Box<Animal> if Dog extends Animal)

Why

Variance determines type compatibility: covariant types preserve subtype direction, contravariant types reverse it. TypeScript infers this structurally by default, but explicit annotations are faster and enforce correctness.

Gotchas

  • Variance annotations are only available in TypeScript 4.7+.
  • An incorrect variance annotation makes the type unsound — the compiler trusts the annotation.
  • Variance annotations only apply to interfaces and type aliases, not class type parameters.

Revisions (0)

No revisions yet.