Background: In JavaScript, callback functions are used everywhere, but their signatures are often non-obvious. In TypeScript, it is important to explicitly state the types of parameters and return values; otherwise, it is easy to create holes in type safety.
Problem: Incorrect or loose typing of callbacks leads to undefined types of arguments and results, complicates working with context (this), breaks automatic error checking by the compiler, and hampers refactoring.
Solution: It is necessary to explicitly define the type of the callback function, specify the types of passed parameters, correctly handle optional arguments and return values, and explicitly specify the context type if necessary.
Code example:
type Callback = (error: Error | null, result?: string) => void; function doAsyncWork(data: string, cb: Callback): void { setTimeout(() => { if (data === '') cb(new Error('Empty string')); else cb(null, data.toUpperCase()); }, 100); }
Key features:
What happens if you do not specify the return type of the callback?
TypeScript will accept any return type (e.g., undefined, void, Promise), which can lead to surprises in asynchronous chains or when returning "default" values.
type BadCallback = (data: string) => any; // any result, no control
Can you write a callback as Function or (...args: any[]) => any?
No. This removes all type safety, losing information about the number of parameters, their types, and the return type. This approach is more costly than abandoning TypeScript altogether.
How to type a function with this context?
Use the first parameter this in the function signature or cast through bind. For example:
interface ClickCallback { (this: HTMLElement, event: MouseEvent): void; } const handler: ClickCallback = function (event) { this.textContent = 'ok'; };
In a project, the callback was declared as (...args: any[]) => any. When business logic was updated, the signature changed, and the callback stopped passing necessary arguments; bugs surfaced only in production.
Pros:
Cons:
Strict types were implemented: callback interfaces were described, and the type of this and return type were explicitly specified. The compiler started catching errors before deployment, refactoring was simplified, and bug fixing support improved.
Pros:
Cons: