TypeScript: стрелочные функции с обобщениями – Руководство
Изучите полный синтаксис стрелочных функций TypeScript с обобщениями. Узнайте, как писать обобщенные функции и применять лучшие практики.
Какой синтаксис используется для стрелочных функций TypeScript с обобщениями?
В справочнике TypeScript пока нет информации о стрелочных функциях с обобщениями. Обычные функции можно типизировать с помощью обобщений так:
function identity<T>(arg: T): T {
return arg;
}
Какой эквивалентный синтаксис для стрелочных функций?
Типобезопасные стрелочные функции в TypeScript используют тот же синтаксис параметров типа, что и обычные функции, но в форме стрелочной функции. Эквивалент стрелочной функции для вашего примера выглядит так:
const identity = <T>(arg: T): T => arg;
Содержание
- Основной синтаксис стрелочной функции с обобщениями
- Несколько параметров типа
- Вариации синтаксиса стрелочных функций
- Практические примеры и варианты использования
- Лучшие практики и соображения
Основной синтаксис стрелочной функции с обобщениями
Базовый синтаксис стрелочных функций с обобщениями в TypeScript выглядит так:
const functionName = <T>(parameter: T): T => {
// тело функции
return parameter;
};
Ключевые отличия от обычных функций:
- ключевое слово
constвместоfunction - стрелка
=>вместо фигурных скобок тела функции - параметр типа
<T>размещается перед списком параметров - аннотация типа возвращаемого значения следует после списка параметров
Прямое сравнение:
Обычная функция:
function identity<T>(arg: T): T {
return arg;
}
Эквивалентная стрелочная функция:
const identity = <T>(arg: T): T => arg;
Обе функции работают одинаково, но используют разный синтаксис. Стрелочная версия более лаконична и часто используется в современных кодовых базах TypeScript.
Несколько параметров типа
Стрелочные функции могут обрабатывать несколько параметров типа так же, как и обычные функции:
// Обычная функция с несколькими обобщениями
function createPair<T, U>(first: T, second: U): [T, U] {
return [first, second];
}
// Эквивалентная стрелочная функция
const createPair = <T, U>(first: T, second: U): [T, U] => [first, second];
Можно также использовать более сложные ограничения обобщений:
const getProperty = <T, K extends keyof T>(obj: T, key: K): T[K] => {
return obj[key];
};
Вариации синтаксиса стрелочных функций
Стрелочные функции предлагают несколько синтаксических вариантов, которые работают с обобщениями:
Стрелочные функции с одной строкой
Для простых операций можно использовать лаконичный синтаксис одной строки:
const identity = <T>(arg: T): T => arg;
const double = <T extends number>(value: T): T => value * 2;
Многострочные стрелочные функции
Для более сложной логики используйте блоковый синтаксис:
const processArray = <T>(items: T[]): T[] => {
const result = [...items];
// Дополнительная логика обработки
result.reverse();
return result;
};
Стрелочные функции с необязательными параметрами
Стрелочные функции без проблем работают с необязательными параметрами:
const greet = <T extends string>(name: T, greeting?: string): string => {
return greeting ? `${greeting}, ${name}!` : `Hello, ${name}!`;
};
Стрелочные функции с rest-параметрами
const concatAll = <T>(...items: T[]): T[] => {
return items.reduce((acc, item) => [...acc, item], []);
};
Практические примеры и варианты использования
Функции высшего порядка с обобщениями
Стрелочные функции особенно полезны для функций высшего порядка:
const pipe = <T>(...fns: Array<(arg: T) => T>) => (value: T): T => {
return fns.reduce((acc, fn) => fn(acc), value);
};
// Использование
const addOne = <T extends number>(x: T): T => (x + 1) as T;
const multiplyByTwo = <T extends number>(x: T): T => (x * 2) as T;
const addOneAndDouble = pipe(addOne, multiplyByTwo);
console.log(addOneAndDouble(5)); // Вывод: 12
Стрелочные функции с выводом типов
Вывод типов TypeScript работает отлично с обобщёнными стрелочными функциями:
const mapArray = <T, U>(array: T[], mapper: (item: T) => U): U[] => {
return array.map(mapper);
};
// Вывод типов работает здесь
const numbers = [1, 2, 3, 4, 5];
const doubled = mapArray(numbers, x => x * 2); // Тип: number[]
Стрелочные функции в React-компонентах
В React обобщённые стрелочные функции часто используются для пользовательских хуков:
const useLocalStorage = <T>(key: string, initialValue: T) => {
const [storedValue, setStoredValue] = useState<T>(() => {
try {
const item = window.localStorage.getItem(key);
return item ? JSON.parse(item) : initialValue;
} catch (error) {
return initialValue;
}
});
const setValue = (value: T | ((val: T) => T)) => {
try {
const valueToStore = value instanceof Function ? value(storedValue) : value;
setStoredValue(valueToStore);
window.localStorage.setItem(key, JSON.stringify(valueToStore));
} catch (error) {
console.error(error);
}
};
return [storedValue, setValue] as const;
};
Лучшие практики и соображения
Когда использовать стрелочные функции с обобщениями
-
Предпочтение стрелочным функциям для:
- Простых операций одной строкой
- Функций высшего порядка
- Когда нужна лексическая привязка
this - При работе с функциональными паттернами
-
Рассмотрите обычные функции для:
- Сложных функций, которым нужна привязка
this - Когда нужна подъем функции (hoisting)
- При написании методов класса
- Сложных функций, которым нужна привязка
Конвенции именования параметров типа
Используйте описательные имена параметров типа, когда они представляют конкретные типы:
// Хорошо
const getProperty = <T, K extends keyof T>(obj: T, key: K): T[K] => obj[key];
// Более описательно
const getPropertyValue = <ObjectType, KeyType extends keyof ObjectType>(
object: ObjectType,
key: KeyType
): ObjectType[KeyType] => object[key];
Обработка сложных ограничений обобщений
Стрелочные функции отлично работают с сложными ограничениями:
const sortBy = <T>(array: T[], key: keyof T): T[] => {
return [...array].sort((a, b) => {
if (a[key] < b[key]) return -1;
if (a[key] > b[key]) return 1;
return 0;
});
};
Производительность
Стрелочные функции с обобщениями имеют те же характеристики производительности, что и обычные функции. Проверка типов происходит во время компиляции, поэтому производительность во время выполнения идентична.
Обработка ошибок в обобщённых стрелочных функциях
const safeParse = <T>(json: string, defaultValue: T): T => {
try {
return JSON.parse(json);
} catch {
return defaultValue;
}
};
Источники
- TypeScript Introduction - Type Parameters and Generic Functions
- Do Parentheses Matter in Arrow Functions? A TypeScript Deep Dive
- Arrow Function Syntax Guidelines
Заключение
Стрелочные функции с обобщениями в TypeScript следуют простому шаблону синтаксиса, который сохраняет согласованность с обычными обобщёнными функциями, при этом предлагая преимущества синтаксиса стрелочных функций. Ключевые выводы:
- Используйте
<T>перед списком параметров для параметров типа - Стрелочные функции предоставляют более лаконичный синтаксис для обобщённых операций
- Они беспрепятственно работают с системой вывода типов TypeScript
- Доступны как однострочные, так и многострочные варианты синтаксиса
- Стрелочные функции особенно подходят для функций высшего порядка и функциональных паттернов
Синтаксис const identity = <T>(arg: T): T => arg; обеспечивает ту же типобезопасность и функциональность, что и обычная функция, но при этом улучшает читаемость и лаконичность во многих сценариях.