Covariance means a generic type preserves the direction of subtyping. If A is a subtype of B, then Generic<A> is a subtype of Generic<B>. It allows safe substitution when reading values.
Click to reveal answer
beginner
What does contravariance mean in generic types?
Contravariance means a generic type reverses the direction of subtyping. If A is a subtype of B, then Generic<B> is a subtype of Generic<A>. It is useful when a generic type is used for input (like function parameters).
Click to reveal answer
beginner
What is invariance in generic types?
Invariance means no subtyping relationship is preserved between generic types. If A is a subtype of B, Generic<A> and Generic<B> are unrelated types. This happens when a generic type is used for both input and output.
Click to reveal answer
intermediate
How does TypeScript handle variance in function types?
TypeScript treats function parameter types as contravariant and return types as covariant. This means you can pass a function expecting a more general parameter where a more specific one is expected, and return a more specific type than expected.
Click to reveal answer
beginner
Why is understanding generic type variance important?
It helps you write safer and more flexible code by knowing when you can substitute one generic type for another. It prevents bugs related to incorrect assumptions about type relationships in generics.
Click to reveal answer
If Dog is a subtype of Animal, which is true for a covariant generic Box<T>?
A<code>Box<Dog></code> is a subtype of <code>Box<Animal></code>
B<code>Box<Animal></code> is a subtype of <code>Box<Dog></code>
C<code>Box<Dog></code> and <code>Box<Animal></code> are unrelated
DBoth are the same type
✗ Incorrect
Covariance preserves subtyping direction, so Box<Dog> is a subtype of Box<Animal>.
Which variance applies when a generic type is used only as a function parameter?
ACovariance
BInvariance
CBivariance
DContravariance
✗ Incorrect
Function parameters are contravariant because the subtyping direction reverses for inputs.
What happens to variance if a generic type is used both as input and output?
AContravariant
BInvariant
CCovariant
DBivariant
✗ Incorrect
Using a generic type both as input and output makes it invariant, so no subtyping relationship is preserved.
In TypeScript, function return types are:
ACovariant
BContravariant
CInvariant
DUnrelated
✗ Incorrect
Function return types are covariant, meaning they preserve subtyping direction.
Why might ignoring variance cause bugs in TypeScript generics?
ABecause it causes syntax errors
BBecause it makes code run slower
CBecause it can allow unsafe substitutions of types
DBecause it prevents using generics
✗ Incorrect
Ignoring variance can allow substituting incompatible types, leading to runtime errors.
Explain covariance, contravariance, and invariance in generic types with simple examples.
Think about how subtyping changes when used for input or output.
You got /3 concepts.
Describe how TypeScript treats variance in function types and why it matters.
Consider how functions accept inputs and produce outputs.
You got /3 concepts.
Practice
(1/5)
1.
Which of the following best describes covariance in TypeScript generic types?
easy
A. It allows a generic type to accept a supertype where a subtype is expected.
B. It allows a generic type to accept a subtype where a supertype is expected.
C. It restricts generic types to only accept exact types without substitution.
D. It means generic types cannot be assigned to each other regardless of relation.
Solution
Step 1: Understand covariance meaning
Covariance means you can use a more specific type (subtype) where a more general type (supertype) is expected.
Step 2: Apply to generic types
In TypeScript, covariance allows substituting a subtype for a supertype safely in generics.
Final Answer:
It allows a generic type to accept a subtype where a supertype is expected. -> Option B
Quick Check:
Covariance = subtype for supertype [OK]
Hint: Covariance means subtype can replace supertype [OK]
Common Mistakes:
Confusing covariance with contravariance
Thinking covariance restricts substitution
Assuming covariance means exact type only
2.
Which of the following is the correct syntax to declare a generic function with contravariant parameter in TypeScript?
function process<T>(input: T): void { /* ... */ }
easy
A. function process(input: T): void { }
B. function process(input: T): void { }
C. function process<T>(input: T): void { }
D. function process(input: T): void { }
Solution
Step 1: Recall TypeScript generic variance syntax
TypeScript does not use in or out keywords like some languages for variance.
Step 2: Check valid generic function syntax
The correct syntax is simply function process<T>(input: T): void { } without variance keywords.
Final Answer:
function process<T>(input: T): void { } -> Option C
Quick Check:
No variance keywords in TypeScript generics [OK]
Hint: TypeScript uses no in/out keywords for generics [OK]
A. Assigning animalPrinter to dogPrinter causes a type error due to invariance.
B. The print method signature is incorrect and causes a syntax error.
C. There is no error; the code runs and prints 'Buddy'.
D. The dogPrinter variable is not declared properly.
Solution
Step 1: Analyze variance of Printer<T>
Printer<T> has a method accepting T as parameter, making it contravariant in T.
Step 2: Check assignment direction
Assigning Printer<Animal> to Printer<Dog> is invalid because contravariance requires the opposite direction.
Final Answer:
Assigning animalPrinter to dogPrinter causes a type error due to invariance. -> Option A
Quick Check:
Function parameter generics are contravariant [OK]
Hint: Function parameters are contravariant; assignment direction matters [OK]
Common Mistakes:
Ignoring contravariance in function parameters
Assuming generic interfaces are always covariant
Confusing parameter and return type variance
5.
You want to create a generic event handler interface in TypeScript that accepts events of type T. The handler should be able to accept handlers for supertypes of T (contravariance). Which of the following interface declarations correctly models this behavior?
hard
A. type EventHandler<T> = (event: T) => void;
B. interface EventHandler<in T> { handle(event: T): void; }
C. interface EventHandler<T> { handle(event: T): T; }
D. interface EventHandler<T> { handle(event: T): void; }
Solution
Step 1: Understand contravariance in function parameters
Function parameters are contravariant, so a function type like (event: T) => void models contravariance naturally.
Step 2: Compare interface and type alias
Interfaces with methods are invariant by default in TypeScript, but function types are contravariant in parameters, so using a type alias for a function is correct.
Step 3: Check invalid syntax options
interface EventHandler<in T> { handle(event: T): void; } uses in keyword which TypeScript does not support; interface EventHandler<T> { handle(event: T): T; } changes return type, losing contravariance.
Final Answer:
type EventHandler<T> = (event: T) => void; -> Option A
Quick Check:
Function types are contravariant in parameters [OK]
Hint: Use function types for contravariant parameters [OK]
Common Mistakes:
Using unsupported 'in' keyword in generics
Assuming interfaces are contravariant by default
Changing return type affects variance incorrectly
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.