Полезные типы TypeScript — те, которые стоит запоминать (и остальные)
Частичный, Выбор, Пропуск, Запись, Тип возвращаемого значения, Параметры, Ожидаемый — восемь полезных типов с примерами до и после и честным мнением о том, какие из них вы будете использовать каждый день.
Вы, вероятно, уже читали страницу документации по TypeScript, на которой перечислены более 20 полезных типов в алфавитном порядке, каждый из которых объясняется в одном предложении, и это оставило вас с вопросом, какие из них стоит действительно запомнить, а какие предназначены исключительно для разработчиков фреймворков. Вот более честный вариант: восемь типов, с конкретными примерами до и после, и прямой ответ о том, какие из них используются ежедневно, а какие — редко.
Если вы начинаете с чистого JSON и ещё не написали свои интерфейсы, то конвертер JSON в TypeScript поможет вам получить базовый интерфейс за несколько секунд — затем вернитесь сюда, чтобы добавить эти полезные типы.
Partial — ежедневное использование. Изучайте его первым.
Сделает все свойства в T необязательными. Классический случай — обновления в стиле PATCH, когда вы отправляете только поля, которые изменились.
// Before: manually duplicating the interface with optional versions of everything
interface UserUpdate {
name?: string;
email?: string;
age?: number;
}
// After: Partial derives it from the source of truth
interface User {
name: string;
email: string;
age: number;
}
function updateUser(id: string, updates: Partial<User>) {
// updates.name is string | undefined — TypeScript knows
}
Проблема с версией «до»: если вы добавляете поле в User, вам нужно помнить, чтобы добавить его и в UserUpdate . С помощью Partial<User>добавление поля в исходный интерфейс автоматически делает его доступным для обновлений. Типы остаются синхронизированными.
Required — ежемесячное использование, но помогает в одном конкретном сценарии.
Противоположность Partial — удаляет все ? из типа. Наиболее полезно после валидации: вы получаете объект с нестрогим типом конфигурации, проверяете, что все поля присутствуют, и хотите, чтобы TypeScript перестал предлагать, что все поля могут быть неопределёнными.
// Before: after validating, you still fight undefined checks everywhere
interface Config {
apiUrl?: string;
timeout?: number;
retries?: number;
}
function initApp(config: Config) {
config.apiUrl?.trim(); // need optional chaining even after checking
}
// After: Required signals "this has been validated, stop warning me"
function validateAndInit(raw: Config): void {
if (!raw.apiUrl) throw new Error("apiUrl required");
if (!raw.timeout) throw new Error("timeout required");
if (!raw.retries) throw new Error("retries required");
const config = raw as Required<Config>;
config.apiUrl.trim(); // no optional chaining needed
}
Честное замечание: Required<T> не выполняет валидацию на уровне выполнения — вам всё равно нужно писать проверки. Оно лишь меняет то, что TypeScript считает в дальнейшем. Используйте его для передачи сигнала «это уже было валидировано» на уровне типов.
Pick — ежедневное использование. Выбираете, что хотите.
Создаёт новый тип, содержащий только свойства, которые вы указываете из T. Полезно, когда нужно получить подмножество более крупного интерфейса — формы публичного API, представления, сериализованные ответы.
// Before: manually maintaining a separate interface that drifts from User
interface UserPublicProfile {
name: string;
bio: string;
avatarUrl: string;
}
// After: Pick stays in sync with the source
interface User {
id: string;
name: string;
email: string; // private — shouldn't go to clients
passwordHash: string; // definitely private
bio: string;
avatarUrl: string;
}
type UserPublicProfile = Pick<User, "name" | "bio" | "avatarUrl">;
Pick — правильный инструмент, когда список свойств, которые вы хотите короче, чем список, который вам нужно exclude. Когда ситуация наоборот, обращайтесь к Omit.
Omit — ежедневное использование. Указывайте, что не хотите.
Дополнение к Pick — создаёт тип с всеми свойствами из T кроме тех, которые вы указываете. Когда у вас есть большой интерфейс и только несколько полей, которые нужно исключить, Omit делает намерение более понятным, чем перечисление всех нужных полей.
// Before: manually listing every field except the sensitive ones
// Easy to miss a new field added to User later
interface UserForClient {
id: string;
name: string;
email: string;
bio: string;
avatarUrl: string;
// passwordHash intentionally omitted — but a future dev might not know that
}
// After: Omit states the exclusion explicitly
type UserForClient = Omit<User, "passwordHash">;
// If User gains a new "address" field, UserForClient gets it automatically
Одно из того, что ни Pick, ни Omit не делают: изменение типа отдельных свойств. Если вы хотите выбрать поля и и изменить их типы, вам нужно обратиться к отображающему типу, который — это совершенно другой инструмент.
Record — ежедневное использование. Типизированный словарь.
Создаёт тип объекта, где все ключи имеют тип K и все значения имеют тип V. Реальный выигрыш появляется, когда K является объединённым типом — TypeScript выдаст ошибку, если вы упустите ключ. Общие индексные сигнатуры безусловно принимают неполные объекты; Record с объединённым ключом не допускает этого.
// Before: index signature with no exhaustiveness checking
const rolePermissions: { [key: string]: string[] } = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
// forgot "viewer" — TypeScript doesn't notice
};
// After: Record with a union key enforces completeness
type Role = "admin" | "editor" | "viewer";
const rolePermissions: Record<Role, string[]> = {
admin: ["read", "write", "delete"],
editor: ["read", "write"],
viewer: ["read"],
// TypeScript error if any Role is missing
// TypeScript error if you try to add an unknown key
};
Проверка исчерпывающего покрытия — настоящий выигрыш. Это важно, когда ключи представляют что-то значимое, например роли, типы событий, HTTP-методы или коды состояний — любые случаи, где отсутствие значения — это ошибка, а не просто пропуск.
ReturnType — ежедневное использование, если вы используете функции сторонних библиотек.
Извлекает тип возвращаемого значения функции. Наиболее полезно при использовании функции из библиотеки и желании типизировать переменную, содержащую её результат — без необходимости импортировать тип возвращаемого значения отдельно (что библиотеки не всегда делают).
// Before: manually annotating the return type — it can drift
function getCurrentUser() {
return { id: "u1", name: "Alice", roles: ["admin"] as const };
}
let cachedUser: { id: string; name: string; roles: readonly string[] };
// If getCurrentUser's return changes, this annotation doesn't update automatically
// After: ReturnType derives it and keeps in sync
type CurrentUser = ReturnType<typeof getCurrentUser>;
let cachedUser: CurrentUser;
// Especially useful with unexported library types:
import { useQuery } from "@tanstack/react-query";
type QueryResult = ReturnType<typeof useQuery>;
// No need to figure out what QueryObserverResult<...> looks like or import it
Parameters — редкое использование. В основном для обёрток.
Извлекает типы параметров функции в виде кортежа. Честный взгляд: вы не будете использовать это ежедневно, если не пишете много обёрток или высокопроизводительных утилит. Но когда вам это нужно, нет чистого альтернативы.
// Before: manually duplicating parameter types in the wrapper
function createEvent(
type: string,
payload: Record<string, unknown>,
timestamp: number
) { /* ... */ }
// Every time createEvent changes, this wrapper needs a manual update:
function loggedCreateEvent(
type: string,
payload: Record<string, unknown>,
timestamp: number
) {
console.log("Creating event:", type);
return createEvent(type, payload, timestamp);
}
// After: Parameters keeps the wrapper in sync automatically
function loggedCreateEvent(...args: Parameters<typeof createEvent>) {
console.log("Creating event:", args[0]);
return createEvent(...args);
}
Паттерн расширения и остатка (...args: Parameters<F>) — основной идиоматический подход. Он также встречается в тестовых моках: jest.fn<ReturnType<F>, Parameters<F>>() позволяет создать полностью типизированный мок без необходимости импортировать сигнатуру функции отдельно.
Awaited — используйте, когда нужно развернуть типы Promise без вызова функции.
Добавлено в TypeScript 4.5 (выпущено в ноябре 2021 года). Рекурсивно разворачивает Promise<T> для получения T. До его появления, получение развернутого типа из асинхронной функции означало написание условного типа: ReturnType<F> extends Promise<infer U> ? U : never — что нарушает работу при двойном обёртывании Promise и трудно читается в сравнениях.
// Before: conditional type to unwrap — breaks on nested Promises
async function fetchUser(id: string) {
const res = await fetch(`/api/users/${id}`);
return res.json() as { id: string; name: string; email: string };
}
type FetchedUser =
ReturnType<typeof fetchUser> extends Promise<infer U> ? U : never;
// Works for Promise<T> but not Promise<Promise<T>>
// After: Awaited handles both cases cleanly
type FetchedUser = Awaited<ReturnType<typeof fetchUser>>;
// Awaited recursively unwraps:
type A = Awaited<Promise<string>>; // string
type B = Awaited<Promise<Promise<string>>>; // string
type C = Awaited<string>; // string (no-op on non-Promise)
Комбинация Awaited<ReturnType<typeof fn>> стоит запомнить как единое целое — она охватывает 90% случаев извлечения типов асинхронных функций в приложениях.
Краткое руководство
| Полезный тип | Что делает | Частота использования | Основное назначение |
|---|---|---|---|
Partial<T> | Все свойства становятся необязательными | Еженедельно | Обновления в стиле PATCH |
Required<T> | Все необязательные свойства становятся обязательными | Ежемесячно | Сигнал «это завершено» после валидации |
Pick<T, K> | Сохраняются только названные свойства | Еженедельно | Формы публичного API, представления |
Omit<T, K> | Удаляются названные свойства | Еженедельно | Удаление чувствительных или ненужных полей |
Record<K, V> | Объект с ключами типа K и значениями типа V | Еженедельно | Типизированные словари с проверкой исчерпывающего покрытия |
ReturnType<F> | Извлекает тип возвращаемого значения функции | Ежедневное (особенно при работе с библиотеками) | Типизирует переменную, содержащую результат из неимпортированного или неэкспортированного возвращаемого типа |
Parameters<F> | Извлекает типы параметров функции в виде кортежа | Редкое использование | Обёртки функций, типизированные моки |
Awaited<T> | Рекурсивно разворачивает типы Promise | Редкое использование | Получение развернутого типа из асинхронной функции |
Те, что не указаны в этом списке
TypeScript также предоставляет Readonly<T>, NonNullable<T>, Extract<T,U>, Exclude<T,U>, InstanceType<C>, ConstructorParameters<C>и несколько типов шаблонных строк. Они реальны и иногда полезны, но встречаются в коде библиотек, универсальных утилит и метапрограммирования на уровне типов — не в типичной логике приложений. Если вы запомнили восемь типов, перечисленных выше, изучайте остальные, когда вам действительно понадобятся.
Основная идея одинакова для всех из них: описывает преобразование существующего типа, а не его дублирование. Конкретные названия полезных типов — это просто словарь для выражения этой цели на уровне TypeScript.
Вам также может понравиться
Установите наши расширения
Добавьте инструменты ввода-вывода в свой любимый браузер для мгновенного доступа и более быстрого поиска
恵 Табло результатов прибыло!
Табло результатов — это интересный способ следить за вашими играми, все данные хранятся в вашем браузере. Скоро появятся новые функции!
Подписаться на новости
все Новые поступления
всеОбновлять: Наш последний инструмент was added on Июн 26, 2026
