TypeScript стал отраслевым стандартом для масштабной веб-разработки. Хотя большинство разработчиков знают основы интерфейсов и типов, настоящая сила заключается в продвинутой системе типов. Вот 5 паттернов, которые выделят вас как опытного инженера.
1. Generic Constraints
Generics — мощный инструмент, но иногда нужно ограничить то, что может быть передано. extends — ваш помощник в этом.
interface HasId { id: string; } function getById<T extends HasId>(list: T[], id: string): T | undefined { return list.find((item) => item.id === id); }
Гарантируя, что T расширяет HasId, мы обеспечиваем безопасность доступа к .id внутри функции.
2. Conditional Types
Условные типы позволяют создавать неоднородные маппинги типов. Синтаксис похож на тернарный оператор в JavaScript.
type IsString<T> = T extends string ? true : false; type A = IsString<string>; // true type B = IsString<number>; // false
Практический пример — фильтрация типов из объединения:
type Diff<T, U> = T extends U ? never : T; type NonNullable<T> = Diff<T, null | undefined>;
3. Mapped Types
Mapped types позволяют создавать новые типы на основе существующих, преобразуя свойства.
type ReadOnly<T> = { readonly [P in keyof T]: T[P]; }; interface User { name: string; age: number; } type ReadOnlyUser = ReadOnly<User>;
Вы также можете добавлять или удалять модификаторы:
type Mutable<T> = { -readonly [P in keyof T]: T[P]; };
4. Template Literal Types
Появившиеся в TypeScript 4.1, они позволяют манипулировать строковыми типами напрямую.
type World = 'world'; type Greeting = `hello ${World}`; // "hello world" type Color = 'red' | 'blue'; type Quantity = 'light' | 'dark'; type Palette = `${Quantity}-${Color}`; // "light-red" | "light-blue" | "dark-red" | "dark-blue"
Это невероятно полезно для типизации строк, следующих определённому шаблону, например, CSS-классов или имён событий.
5. Ключевое слово infer
Ключевое слово infer в условных типах позволяет извлекать типы из других типов.
type ReturnType<T> = T extends (...args: any[]) => infer R ? R : any; function check(): boolean { return true; } type CheckReturn = ReturnType<typeof check>; // boolean
Здесь мы просим TypeScript «вывести» тип возвращаемого значения R функции и вернуть его.
Заключение
Освоение этих паттернов позволяет писать библиотеки и утилиты, которые надёжны и обеспечивают отличный опыт разработчика (DX). Цель продвинутого TypeScript — не сложность ради сложности, а безопасность и выразительность.