Строгая типизация функций как параметров в TypeScript: как объявить тип для callback?
Сигнатуры функций в TypeScript
Да, в TypeScript можно строго типизировать функции, передаваемые как параметры. Для этого используются сигнатуры функций (function type expressions). Они позволяют явно указать, какие аргументы принимает функция и что возвращает.
Базовый синтаксис
Сигнатура функции записывается в формате:
(параметры) => возвращаемый_тип
Вот как исправить ваш пример:
function processData(
data: number[],
callback: (result: number[]) => void
): void {
const result = data.map(item => item * 2);
callback(result);
}
// Использование:
processData([1, 2, 3], (result) => {
result.forEach(r => console.log(r));
});
Здесь (result: number[]) => void означает:
- Функция принимает один параметр — массив чисел (
number[]) - Функция ничего не возвращает (
void)
Более сложные примеры
Рассмотрим несколько сценариев:
Callback с возвратом значения
function transformData(
data: number[],
transformer: (item: number, index: number) => string
): string[] {
return data.map(transformer);
}
const result = transformData([1, 2, 3], (num, idx) => `Index ${idx}: ${num}`);
// result: ["Index 0: 1", "Index 1: 2", "Index 2: 3"]
Callback с несколькими параметрами
function fetchData(
url: string,
onSuccess: (data: any) => void,
onError: (code: number, message: string) => void
): void {
// ... логика запроса
}
Опциональный callback
function processWithCallback(
data: number[],
callback?: (result: number[]) => void
): void {
const result = data.map(x => x * 2);
if (callback) {
callback(result);
}
}
Создание собственных типов для callback
Если один и тот же callback используется в нескольких местах, лучше вынести его в отдельный тип:
type DataCallback = (result: number[]) => void;
function processData(data: number[], callback: DataCallback): void {
// ...
}
function logData(data: number[], callback: DataCallback): void {
// ...
}
Или с помощью интерфейса:
interface CallbackInterface {
(result: number[]): void;
}
function processData(data: number[], callback: CallbackInterface): void {
// ...
}
Типизация методов объектов
Если callback — метод объекта, можно использовать контекст:
interface EventHandler {
handleEvent: (event: string) => void;
}
function registerHandler(handler: EventHandler): void {
handler.handleEvent('click');
}
Проверка на практике
TypeScript будет ругаться, если вы попытаетесь передать функцию с неправильной сигнатурой:
// Ошибка! Функция должна принимать number[], а не string[]
processData([1, 2, 3], (result: string[]) => {});
// Ошибка! Функция должна возвращать void, а не number
processData([1, 2, 3], (result) => 42);
// Ошибка! Слишком много параметров
processData([1, 2, 3], (result, extra) => {});
Таким образом, строгая типизация callback'ов в TypeScript полностью решает вашу проблему и даёт все преимущества статической проверки типов.
<<Использование generic-типов для callback
Если вы хотите сделать callback более гибким и переиспользуемым, можно использовать обобщённые типы (generics). Это позволяет создавать функции, которые работают с разными типами данных, сохраняя строгую типизацию.
function processData<T>(
data: T[],
callback: (item: T, index: number) => void
): void {
data.forEach((item, index) => callback(item, index));
}
// Работает с числами
processData([1, 2, 3], (num, idx) => console.log(num * idx));
// Работает со строками
processData(['a', 'b', 'c'], (str, idx) => console.log(`${idx}: ${str}`));
// Работает с объектами
interface User { name: string; age: number; }
processData<User>(
[{ name: 'Alice', age: 30 }],
(user) => console.log(user.name)
);
Также можно типизировать возвращаемое значение callback:
function mapData<T, R>(
data: T[],
callback: (item: T, index: number) => R
): R[] {
return data.map(callback);
}
const numbers = mapData([1, 2, 3], (num) => num * 2); // number[]
const strings = mapData([1, 2, 3], (num) => `Number: ${num}`); // string[]
Этот подход особенно полезен, когда вы пишете библиотечные функции или утилиты, которые должны работать с разными типами данных, сохраняя при этом полную типовую безопасность.