Как правильно типизировать колбэк-функцию в параметрах метода TypeScript?
Основной подход: явное описание сигнатуры функции
В TypeScript лучший способ типизировать колбэк — это явно описать его сигнатуру, используя стрелочную функцию в качестве типа. Это даёт полную проверку типов и автодополнение в IDE.
Для вашего примера с DataProcessor правильное решение будет таким:
class DataProcessor {
process(data: number[], callback: (result: number[]) => void) {
const result = data.map(x => x * 2);
callback(result);
}
}
// Использование:
const processor = new DataProcessor();
processor.process([1, 2, 3], (result) => {
console.log(result); // result: number[]
});
Здесь (result: number[]) => void означает, что колбэк принимает один аргумент типа number[] и ничего не возвращает (void). TypeScript будет проверять:
- Что колбэк вызывается только с одним аргументом типа
number[] - Что колбэк не возвращает значение (или возвращает
undefined) - Что при вызове метода передаётся функция с правильной сигнатурой
Использование type alias для переиспользования
Если один и тот же тип колбэка используется в нескольких местах, лучше вынести его в отдельный тип:
type DataCallback = (result: number[]) => void;
class DataProcessor {
process(data: number[], callback: DataCallback) {
// ...
}
processAsync(data: number[], callback: DataCallback) {
// ...
}
}
Типизация с возвращаемым значением
Если колбэк должен что-то возвращать, укажите тип возврата:
type TransformCallback = (item: number) => string;
function transformArray(arr: number[], callback: TransformCallback): string[] {
return arr.map(callback);
}
const result = transformArray([1, 2, 3], (num) => `Number: ${num}`);
// result: string[]
Дополнительные аргументы и опциональность
Колбэк может принимать несколько аргументов или опциональные параметры:
type ErrorFirstCallback = (error: Error | null, data?: string) => void;
function fetchData(callback: ErrorFirstCallback) {
try {
const data = "some data";
callback(null, data);
} catch (err) {
callback(err as Error);
}
}
Важные моменты
- Не используйте
anyилиFunction— они отключают проверку типов - Используйте
voidесли колбэк не должен возвращать значение — это позволяет передавать функции, которые возвращают что-то, но это значение будет проигнорировано - Для опциональных колбэков используйте
callback?: (arg: Type) => voidи проверяйте наличие перед вызовом
Этот подход широко используется в библиотеках TypeScript (например, Array.prototype.map, Promise.then) и обеспечивает максимальную безопасность типов.
Альтернатива: использование обобщённых типов (generics)
Если ваш колбэк может работать с разными типами данных, можно сделать метод обобщённым:
class DataProcessor {
process<T>(data: T[], callback: (item: T, index: number) => void): void {
data.forEach((item, index) => callback(item, index));
}
}
// Использование с числами:
const processor = new DataProcessor();
processor.process([1, 2, 3], (item, index) => {
console.log(item.toFixed(2)); // item: number
});
// Использование со строками:
processor.process(['a', 'b', 'c'], (item, index) => {
console.log(item.toUpperCase()); // item: string
});
Этот подход полезен, когда ваш метод должен быть универсальным и работать с разными типами данных, сохраняя при этом строгую типизацию. Компилятор TypeScript автоматически выведет тип T из переданного массива.
Также можно комбинировать обобщения с несколькими параметрами:
function mapWithCallback<T, R>(
arr: T[],
callback: (item: T) => R
): R[] {
return arr.map(callback);
}
const numbers = mapWithCallback([1, 2, 3], (x) => x * 2); // number[]
const strings = mapWithCallback([1, 2, 3], (x) => String(x)); // string[]
Это даёт максимальную гибкость без потери безопасности типов.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги
Функциональное программирование в PHP: от основ до практики