ProgrammingFullstack Developer

How to implement and correctly type a callback function with parameters that can be optional or have default values? What difficulties might arise and how to avoid them?

Pass interviews with Hintsage AI assistant

Answer.

Background:

Callback functions are a common practice in JS and TS for asynchronous programming and delegating responsibility. In TypeScript, typing such functions is an important part of ensuring safety, especially when parameters can be optional or have default values.

Problem:

In dynamic JS, the lack of typing for callback arguments can lead to value passing errors, confusion with undefined, and incorrect parameter order. In TypeScript, typing is required to avoid such issues, but it can be challenging to maintain all nuances related to optionality, order, and default values from the outside.

Solution:

Explicitly specify the types of all parameters, mark optional parameters with a question mark, and specify default values directly in the function declaration while also ensuring they are correctly described in the type.

Example code:

function fetchData( url: string, callback: (data: any, error?: Error) => void ) { // ... } // Callback with an optional error parameter fetchData('/api', (data, error) => { if (error) { // handling } else { // success } }); // Callback with a default parameter function process( cb: (x: number, y?: number) => void = (x, y = 10) => { /* ... */ } ) { /* ... */ }

Key points:

  • A "?" is used for optional parameters.
  • Default values are specified in the function definition.
  • Typing makes code maintenance easier and reduces the number of errors.

Tricky questions.

Is the consumer of the callback required to explicitly consider all parameters, including optional ones?

No, they can skip optional parameters, and TypeScript won't throw an error — the handling works correctly due to the question mark syntax.

Can the first parameter in the callback be optional while the second is mandatory?

No. Optional parameters must always be at the end of the argument list. Violating this order will lead to a typing error.

What happens if the parameter's optionality is not specified but it's not passed at the call site?

TypeScript will throw an error — if the parameter is mandatory, it must be passed. Only optional or default ones can be omitted.

Common mistakes and anti-patterns

  • Violating the order of optional and mandatory parameters (mandatory first, then optional).
  • Lack of explicit type declaration or using "any" — leads to losing the advantages of TypeScript.
  • Attempting to pass undefined instead of a value and expecting the default to trigger (it only triggers if the argument is absent).

Real-life example

Negative case

Made the second argument of the callback mandatory but did not provide it in the call. Received a compilation error.

Pros:

  • Quickly and easily written code without clarifications.

Cons:

  • Does not compile.
  • Loss of flexibility and confusing responsibility.

Positive case

Typed the callback with an optional parameter:

(cb: (x: number, y?: number) => void)

Or set a default:

f = (x: number, y = 10) => { ... }

Pros:

  • Guarantees the absence of errors when calling callbacks.
  • Readability and maintainability.

Cons:

  • Needs to be attentive to the order of parameters.