patterntypescriptnoneTip
Variance Annotations (in/out) for Generic Type Parameters
Viewed 0 times
TypeScript 4.7+
variancecovariancecontravariancein outgeneric type parameter
Error Messages
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.