← CodeClarityLab Home
Browse by Category
+ added · updated 7d
← Back to glossary

Covariance & Contravariance

typescript 4.7 Advanced

Also Known As

covariance contravariance bivariance variance annotations in out type parameters

TL;DR

Variance describes how subtype relationships on a type's components affect subtype relationships on the whole type — covariant types follow the direction, contravariant types reverse it.

Explanation

Covariance: if Dog extends Animal, then Dog[] extends Animal[] — arrays are covariant in their element type. Producer types (return positions) are covariant. Contravariance: a function that accepts Animal is assignable to one that accepts Dog — function parameters are contravariant (you can pass a more general handler). TypeScript is structurally typed so variance is checked structurally. Method shorthand syntax (method(): void) is bivariant (both directions) for historical reasons — function property syntax (method: () => void) is strictly contravariant, which is safer. TypeScript 4.7 added explicit variance annotations: in T (contravariant), out T (covariant), in out T (invariant).

Diagram

flowchart LR
    subgraph Covariant
        DA[Dog extends Animal]
        DA --> DA2[Dog array extends Animal array]
    end
    subgraph Contravariant
        FN[fn Animal-void]
        FN --> FN2[assignable to fn Dog-void<br/>reverses direction]
    end
    subgraph Invariant
        INV[ReadWrite T<br/>neither sub nor super]
    end

Watch Out

TypeScript's structural typing means variance isn't always enforced as strictly as in nominal type systems like Java. The --strictFunctionTypes flag (included in --strict) enables contravariance for function types.

Common Misconception

Method parameters in TypeScript are always strictly contravariant — method shorthand syntax (m(x: T)) is actually bivariant due to a historical unsoundness. Use function property syntax (m: (x: T) => void) for strict contravariance.

Why It Matters

Misunderstanding variance leads to subtle runtime type errors that TypeScript doesn't catch — particularly when assigning arrays of subtypes to mutable containers or using method shorthand.

Common Mistakes

  • Using method shorthand instead of function property syntax — loses contravariance checking on parameters.
  • Mutating a covariant array — Dog[] assignable to Animal[] seems fine until you push a Cat into it via the Animal[] reference.
  • Expecting a callback accepting a subtype to be assignable to one accepting a supertype — it's actually the reverse (contravariance).
  • Not using in/out variance annotations on generic interfaces where correctness matters.

Avoid When

  • Variance annotations are unnecessary for simple non-generic interfaces.

When To Use

  • Designing generic interfaces that are clearly producers (out T) or consumers (in T) for safer assignments.
  • Library authors ensuring their generic types compose correctly with user-defined subtypes.

Code Examples

💡 Note
Shows the difference between bivariant method shorthand and contravariant function properties, plus TypeScript 4.7 explicit in/out variance annotations.
✗ Vulnerable
// Method shorthand — bivariant (unsound)
interface Processor {
    process(input: Dog): void; // bivariant — accepts Dog or Animal
}

// Mutable covariant array — unsafe
const dogs: Dog[] = [new Dog()];
const animals: Animal[] = dogs;  // OK in TS
animals.push(new Cat());          // Runtime: dogs now contains a Cat!
✓ Fixed
// Function property — strictly contravariant (safe)
interface Processor {
    process: (input: Dog) => void;
}

// TypeScript 4.7 explicit variance
interface Producer<out T> { get(): T }     // covariant — only produces T
interface Consumer<in T> { set(v: T): void } // contravariant — only consumes T
interface Invariant<in out T> { transform(v: T): T } // invariant

Added 11 Apr 2026
Views 37
Rate this term
No ratings yet
🤖 AI Guestbook educational data only
| |
Last 30 days
0 pings W 0 pings T 0 pings F 1 ping S 3 pings S 2 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 1 ping S 0 pings M 0 pings T 0 pings W 0 pings T 1 ping F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 1 ping T 0 pings F 0 pings S 0 pings S 0 pings M 0 pings T 0 pings W 0 pings T
No pings yet today
No pings yesterday
Perplexity 3 Google 2 Unknown AI 2 ChatGPT 1 SEMrush 1 Ahrefs 1
crawler 10
DEV INTEL Tools & Severity
🟢 Low ⚙ Fix effort: High
⚡ Quick Fix
Enable --strict (includes strictFunctionTypes). Prefer function property syntax over method shorthand. Use 'in'/'out' variance annotations on generic interfaces where producer/consumer roles are clear.
📦 Applies To
typescript 4.7 web cli
🔗 Prerequisites
🔍 Detection Hints
\w+\(\w+:
Auto-detectable: ✗ No typescript
🤖 AI Agent
Confidence: Low False Positives: High ✗ Manual fix Fix: High Context: File

✓ schema.org compliant