Ch. 2 · TypeScript

TypeScript Function Variance in Callbacks

TypeScript Function Variance in Callbacks. Learn the reasoning, a practical example, common mistakes and an interview exercise.

~2 min readintermediateupdated Oct 3, 2026

Callback assignability depends on which inputs a function can safely accept. A callback requiring a narrower input cannot handle every value a broader caller may send.

Before you start

You should be comfortable with JavaScript values, functions and objects. Use a TypeScript project with strict checking enabled when trying the examples. Separate what the compiler proves from what must still be checked when values arrive at runtime.

The practical goal is to reason through this situation: A handler accepting only cats is unsafe where callers may pass any animal. Read the walkthrough first, then try the interview exercise before opening its answer. The important part is explaining the decision and its consequences, rather than remembering a definition alone.

Step-by-step walkthrough

Step 1: Read the caller’s promise

If a callback accepts any Animal, its caller may legally pass a dog. A replacement must support that whole input set.

Step 2: Compare required inputs

A callback requiring a Cat also requires cat-specific behavior. Assigning it to an animal callback would let callers violate its assumption.

Step 3: Use an appropriately broad handler

Accept Animal and narrow when necessary. Evaluate examples under strictFunctionTypes and remember method declarations have different checking rules.

Worked scenario

A handler accepting only cats is unsafe where callers may pass any animal.

type Animal = { name: string };
type Cat = Animal & { meow(): void };
const catOnly = (cat: Cat) => cat.meow();
// Under strictFunctionTypes this is rejected:
// const handleAnimal: (a: Animal) => void = catOnly;
const handleAnimal = (animal: Animal) => console.log(animal.name);
TypeScript

A plain Animal with no meow function is a concrete counterexample to the unsafe assignment. Broader input acceptance makes the final handler safe for that caller contract.

Common mistake

Method and function-type checking can differ; compiler options matter.

Verify the behavior

Compile under the supported strict configuration. Explain the failing dog call without relying on variance terminology alone; compare function properties with methods deliberately.

Interview exercise

Explain the unsafe assignment.

Answer and reasoning

The caller could pass a dog. A valid replacement must accept all inputs promised by the original callback contract.

Continue learning

Compare the scenario with the TypeScript interview questions and test your understanding with the TypeScript MCQs. For terminology and implementation details, consult the reference material.

More in TypeScript

read ✓TypeScript · hard

TypeScript Abstract Classes and Contracts

Share behavior with abstract classes, enforce required members, and decide when an interface or composition is the better contract.

~2 min readread →
read ✓TypeScript · mid

TypeScript Enums vs Union Types

Compare enums with unions of string literals: runtime cost, serialization, exhaustiveness and which one fits application code.

~3 min readread →
esc