TYPESCRIPT / CHAPTER 08

Function compatibility and callback promises

Advanced

Make callback types reflect every call the implementation may make.

By the end of this chapter

  • Read parameter and result compatibility
  • Avoid unsafe narrowing of callback inputs
  • Distinguish ignored results from asynchronous completion

The idea

A callback contract describes what the caller may pass and what the callback must support. Under strictFunctionTypes, a function accepting only one narrow subtype cannot safely stand in for a function that may receive a broader union. Use function-valued properties or plain function types in these examples; method syntax has additional variance compatibility rules.

A callback parameter declared optional means its caller is allowed to omit that argument. Do not mark a parameter optional merely because some callback implementations ignore it. TypeScript also permits a value-returning function where a context expects void, because the result is ignored. That does not make an asynchronous callback automatically awaited. If completion matters, express Promise<void> and await it explicitly.

TypeScript example
function each(values: number[], visit: (value: number, index: number) => void) {
  values.forEach((value, index) => visit(value, index));
}
const seen: number[] = [];
each([4, 7], value => { seen.push(value); });
console.log(seen.join(","));
Result
4,7

A callback may ignore extra supplied arguments without requiring the contract to make them optional.

Try it yourself

Write an asyncEach helper whose callback returns Promise<void> and whose own promise waits for every required invocation.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

An implementation always passes an index, but a callback may ignore it. Which callback parameter type best expresses that contract?