Challenge - 5 Problems
Covariance and Contravariance Master
Get all challenges correct to earn this badge!
Test your skills under time pressure!
❓ Predict Output
intermediate2:00remaining
Covariance in TypeScript arrays
What is the output of this TypeScript code snippet?
Typescript
class Animal { name: string = 'animal'; } class Dog extends Animal { bark() { return 'woof'; } } let dogs: Dog[] = [new Dog()]; let animals: Animal[] = dogs; animals.push(new Animal()); console.log(dogs.length);
Attempts:
2 left
💡 Hint
Arrays in TypeScript are covariant, so assigning Dog[] to Animal[] is allowed.
✗ Incorrect
The array dogs is assigned to animals (Animal[]). Pushing a new Animal into animals also affects dogs because they reference the same array. So dogs.length becomes 2.
❓ Predict Output
intermediate2:00remaining
Contravariance in function parameters
What is the output of this TypeScript code?
Typescript
class Animal { name = 'animal'; } class Dog extends Animal { bark() { return 'woof'; } } function feedAnimal(feed: (a: Animal) => void) { feed(new Animal()); } function feedDog(dog: Dog) { console.log('Feeding dog:', dog.name); } feedAnimal(feedDog);
Attempts:
2 left
💡 Hint
Function parameter types are contravariant in TypeScript.
✗ Incorrect
feedDog expects a Dog parameter, but feedAnimal calls feed with an Animal. Passing feedDog to feedAnimal is not allowed because Dog is not a supertype of Animal.
🔧 Debug
advanced2:00remaining
Fix the type error with function assignment
Which option correctly fixes the type error in this code snippet?
Typescript
class Animal { name = 'animal'; } class Dog extends Animal { bark() { return 'woof'; } } let feedAnimal: (a: Animal) => void; let feedDog: (d: Dog) => void = (d) => console.log(d.bark()); feedAnimal = feedDog; // Error here
Attempts:
2 left
💡 Hint
Function parameter types must be contravariant for assignment.
✗ Incorrect
Assigning feedDog to feedAnimal requires feedDog to accept a supertype of Animal, so changing feedDog to accept Animal fixes the error.
❓ Predict Output
advanced2:00remaining
Covariance with readonly arrays
What is the output of this TypeScript code?
Typescript
class Animal { name = 'animal'; } class Dog extends Animal { bark() { return 'woof'; } } let dogs: ReadonlyArray<Dog> = [new Dog()]; let animals: ReadonlyArray<Animal> = dogs; console.log(animals.length);
Attempts:
2 left
💡 Hint
ReadonlyArray is covariant in TypeScript.
✗ Incorrect
ReadonlyArray can be assigned to ReadonlyArray because no mutation is allowed, so covariance is safe.
❓ Predict Output
expert3:00remaining
Complex variance with generics and function types
What is the output of this TypeScript code?
Typescript
class Animal { name = 'animal'; } class Dog extends Animal { bark() { return 'woof'; } } interface Processor<T> { process: (input: T) => T; } let dogProcessor: Processor<Dog> = { process: (d) => { console.log(d.bark()); return d; } }; let animalProcessor: Processor<Animal> = dogProcessor; const result = animalProcessor.process(new Animal()); console.log(result.name);
Attempts:
2 left
💡 Hint
Generic interfaces with function properties are invariant by default.
✗ Incorrect
Processor is invariant in T because process uses T as both input and output. Assigning Processor to Processor is not allowed, causing a compilation error.