Комментарии (3)
🐱
claude-haiku-4.5PrepBro AI3 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Можно ли расширить type
Расширение типов в TypeScript — это создание новых типов на основе существующих. Типы нельзя расширить как классы, но можно создавать новые типы которые их наследуют, комбинируют и расширяют через пересечение и generics.
Основные способы расширения
1. Пересечение типов (&)
Самый распространённый способ расширения типов.
// Базовый тип
type BaseUser = {
id: string;
name: string;
};
// Расширяем через пересечение &
type AdminUser = BaseUser & {
role: 'admin';
permissions: string[];
};
// Использование - AdminUser имеет все поля BaseUser + новые поля
const admin: AdminUser = {
id: '1',
name: 'Alice', // из BaseUser
role: 'admin', // новое
permissions: [] // новое
};
2. Объединение нескольких типов
type Person = {
name: string;
age: number;
};
type Employee = {
employeeId: string;
department: string;
};
// Объединяем оба типа в один
type EmployeePerson = Person & Employee;
const emp: EmployeePerson = {
name: 'Bob',
age: 30,
employeeId: 'EMP123',
department: 'Frontend'
};
3. Union типы для вариантов (|)
type Admin = { role: 'admin'; permissions: string[] };
type User = { role: 'user'; preferences: object };
type Guest = { role: 'guest' };
// Объединение альтернативных типов
type Account = Admin | User | Guest;
const admin: Account = { role: 'admin', permissions: ['edit'] };
const user: Account = { role: 'user', preferences: {} };
const guest: Account = { role: 'guest' };
4. Generics для гибкого расширения
// Базовый generic тип
type Response<T> = {
status: number;
data: T;
};
// Расширение с generic
type SuccessResponse<T> = Response<T> & {
message: 'success';
timestamp: Date;
};
// Использование с разными типами данных
const userResponse: SuccessResponse<{ id: string; name: string }> = {
status: 200,
data: { id: '1', name: 'Alice' },
message: 'success',
timestamp: new Date()
};
const listResponse: SuccessResponse<string[]> = {
status: 200,
data: ['item1', 'item2'],
message: 'success',
timestamp: new Date()
};
5. Условные типы (Conditional Types)
// Если T это массив, вернуть элемент, иначе сам T
type Unwrap<T> = T extends Array<infer U> ? U : T;
type NumArray = Unwrap<number[]>; // number
type StrType = Unwrap<string>; // string
// Практический пример: может быть array или single value
type ApiData<T> = T extends Array<infer U>
? { items: U[]; total: number }
: { item: T };
type UserList = ApiData<User[]>; // { items: User[]; total: number }
type UserSingle = ApiData<User>; // { item: User }
6. Mapped Types для генерации новых типов
type User = { name: string; age: number; email: string };
// Делаем все поля readonly
type ReadonlyUser = {
readonly [K in keyof User]: User[K];
};
// Генерируем getters для каждого поля
type Getters<T> = {
[K in keyof T as `get${Capitalize<string & K>}`]: () => T[K];
};
type UserGetters = Getters<User>;
// Результат:
// {
// getName: () => string;
// getAge: () => number;
// getEmail: () => string;
// }
// Генерируем setters
type Setters<T> = {
[K in keyof T as `set${Capitalize<string & K>}`]: (value: T[K]) => void;
};
7. Keyof для типобезопасности
type User = { name: string; age: number; email: string };
// Получить все ключи как тип
type UserKeys = keyof User; // 'name' | 'age' | 'email'
// Типобезопасная функция с ограничением ключей
function getValue<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
const user = { name: 'Alice', age: 30, email: 'alice@example.com' };
const name = getValue(user, 'name'); // ✅ string
const email = getValue(user, 'email'); // ✅ string
const invalid = getValue(user, 'phone'); // ❌ Ошибка компиляции!
Utility Types для готового расширения
type User = { name: string; age: number; email: string };
// Partial - все поля опциональны
type UserUpdate = Partial<User>; // все поля ?
// Required - все поля обязательны
type UserRequired = Required<UserUpdate>;
// Omit - исключить определённые поля
type UserWithoutEmail = Omit<User, 'email'>; // { name; age }
// Pick - выбрать только эти поля
type UserPreview = Pick<User, 'name' | 'age'>; // { name; age }
// Record - создать объект с определёнными ключами
type Permissions = Record<'read' | 'write' | 'delete', boolean>;
const perms: Permissions = {
read: true,
write: true,
delete: false
};
Interface vs Type для расширения
// Interface можно расширить через extends
interface BaseUser {
id: string;
name: string;
}
interface AdminUser extends BaseUser {
role: 'admin';
permissions: string[];
}
// Type нужно использовать & для расширения
type BaseUserType = { id: string; name: string };
type AdminUserType = BaseUserType & { role: 'admin' };
// Оба способа работают одинаково
const admin: AdminUser = { id: '1', name: 'Alice', role: 'admin', permissions: [] };
const adminType: AdminUserType = { id: '1', name: 'Bob', role: 'admin' };
Практический пример: API Response расширение
// Базовый тип ответа API
type ApiResponse<T> = {
success: boolean;
data?: T;
error?: string;
};
// Расширение для успешного ответа
type ApiSuccess<T> = ApiResponse<T> & {
success: true;
data: T;
timestamp: Date;
};
// Расширение для ошибки
type ApiError = ApiResponse<never> & {
success: false;
error: string;
errorCode: number;
};
// Union - может быть успех или ошибка
type ApiResult<T> = ApiSuccess<T> | ApiError;
// Использование
const success: ApiResult<User> = {
success: true,
data: { id: '1', name: 'Alice' },
timestamp: new Date()
};
const error: ApiResult<User> = {
success: false,
error: 'User not found',
errorCode: 404
};
Глубокое расширение (nested types)
type DeepPartial<T> = {
[K in keyof T]?: T[K] extends object ? DeepPartial<T[K]> : T[K];
};
type User = {
id: string;
profile: {
name: string;
settings: {
theme: string;
notifications: boolean;
};
};
};
// Все уровни вложенности становятся опциональными
type UserUpdate = DeepPartial<User>;
const update: UserUpdate = {
profile: {
settings: {
theme: 'dark'
// notifications не обязательно
}
// name не обязательно
}
// id не обязательно
};
Чек-лист расширения типов
- Пересечение (&) для объединения двух типов
- Union (|) для альтернативных вариантов
- Generics для гибкости и переиспользования
- Mapped types для генерации новых типов из существующих
- Utility types (Partial, Pick, Omit, Required) для готовых решений
- Conditional types для логики на уровне типов
- Keyof для типобезопасности на ключах объектов
Итог: Type в TypeScript нельзя расширить как класс с extends, но можно создавать новые типы используя пересечение (&), union (|), generics, mapped types и utility types. Для частого расширения лучше использовать Interface с extends, или комбинировать несколько техник для максимальной гибкости.