Covariance and contravariance in Typescript - Time & Space Complexity
Let's explore how the time cost changes when using covariance and contravariance in TypeScript functions.
We want to see how the number of operations grows as input types vary.
Analyze the time complexity of the following TypeScript function assignments.
interface Animal { name: string }
interface Dog extends Animal { bark(): void }
let dogFunc: (dog: Dog) => Dog = (dog) => { dog.bark(); return dog; };
let animalFunc: (animal: Animal) => Animal;
// Assigning animalFunc to dogFunc (contravariance in parameter, covariance in return)
animalFunc = dogFunc;
// Using animalFunc
const result = animalFunc({ name: 'Buddy' });
This code shows function type assignments demonstrating covariance and contravariance.
Look for operations that repeat or scale with input size.
- Primary operation: Function call and object property access.
- How many times: Each call runs once per invocation; no loops or recursion here.
Since the function runs once per call, the time grows directly with how many times you call it.
| Input Size (n) | Approx. Operations |
|---|---|
| 10 | 10 function calls |
| 100 | 100 function calls |
| 1000 | 1000 function calls |
Pattern observation: The time grows linearly with the number of calls, not with type complexity.
Time Complexity: O(n)
This means the time grows in a straight line with how many times the function is called.
[X] Wrong: "Covariance and contravariance change how fast the code runs."
[OK] Correct: These concepts affect type safety and assignment rules, not how many steps the code takes to run.
Understanding covariance and contravariance helps you reason about safe code changes and function assignments, a skill that shows clear thinking about types and behavior.
What if the function accepted an array of Dogs instead of a single Dog? How would the time complexity change?