Полезные приёмы TypeScript для повседневной разработки
TypeScript даёт не только автодополнение, но и возможность закладывать инварианты прямо в систему типов. Вот несколько приёмов, которыми я пользуюсь почти в каждом проекте.
Discriminated unions вместо опциональных полей
Вместо набора опциональных полей опишите состояние через дискриминирующее поле:
type RequestState<T> =
| { status: "idle" }
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; error: string };Компилятор сам заставит проверить status, прежде чем обратиться к data или error.
Утилитные типы
Pick, Omit, Partial, Record избавляют от дублирования типов:
type UserPreview = Pick<User, "id" | "name" | "avatarUrl">;
type UpdateUserInput = Partial<Omit<User, "id">>;satisfies вместо явной аннотации
Оператор satisfies проверяет соответствие типу, но сохраняет более узкий выведенный тип:
const routes = {
home: "/",
blog: "/blog",
} satisfies Record<string, `/${string}`>;Zod для границ приложения
Типы TypeScript исчезают во время выполнения. На границах приложения — формы, API-роуты, ответы внешних сервисов — данные нужно валидировать в рантайме. Схема Zod одновременно валидирует значение и выводит из него TypeScript-тип:
const ContactSchema = z.object({
name: z.string().min(2),
email: z.string().email(),
message: z.string().min(10),
});
type ContactInput = z.infer<typeof ContactSchema>;Итог
Строгая типизация — это не бюрократия, а способ переложить часть проверок на компилятор ещё до запуска кода. Чем раньше найдена ошибка, тем дешевле её исправить.