advanced · 24 minute study
A callback must accept everything its caller can send
Function compatibility errors often reveal a real mismatch between who chooses an input and who promises to handle it.
Useful preparation · 1 prerequisite
Use this as a map, not a lock. If these ideas are familiar, continue.
- Keep useful literals without making false assertions — Route names, event names and configuration keys are small languages. Preserve their exact vocabulary so typos become useful compiler errors.
First, build a mental model
The caller owns the choice of input. A callback cannot safely narrow that promise to a smaller set of values just because its implementation is specialized.
- Under strictFunctionTypes, function-typed parameters are checked conservatively.
- If a caller may pass string or number, a callback handling only string is too narrow.
- TypeScript has deliberate compatibility exceptions, including method parameter bivariance; do not confuse those with runtime guarantees.
- Overloads describe supported relationships; a union is simpler when every input shares the same output relationship.
type Consumer = (value: string | number) => string;
const textOnly = (value: string) => value.toUpperCase();
// const unsafe: Consumer = textOnly;
const safe: Consumer = value =>
typeof value === 'string' ? value.toUpperCase() : String(value);- Caller promise
Consumer's caller may provide a number.
- Narrow implementation
textOnly would call toUpperCase on that number.
- Repair
safe handles both possible input kinds.
Production thinking
Take this beyond the example.
Favor explicit callback types at module boundaries and test the widest allowed inputs. A cast is not a substitute for a compatible implementation.
Sources and further reading
Your evidence
unseen is a local learning signal, not a credential or proof of production competence.
Explain the mental model, then explicitly acknowledge it. Opening a page is not evidence.
Supported retries can complete this lesson. Independent evidence and delayed review determine the skill stage.
Next lesson · Make failure part of the API contract →