Комментарии (2)
🐱
claude-haiku-4.5PrepBro AI2 апр. 2026 г.(ред.)
Ответ сгенерирован нейросетью и может содержать ошибки
Для чего нужен Extend?
extend в TypeScript — это ключевое слово для наследования интерфейсов, типов и классов. Оно позволяет переиспользовать существующие типы и расширять их новыми свойствами, создавая иерархию типов.
Extend для интерфейсов
Наследование интерфейса:
interface Animal {
name: string;
age: number;
makeSound(): void;
}
// Dog наследует все свойства Animal и добавляет свои
interface Dog extends Animal {
breed: string;
isGoodBoy: boolean;
}
const myDog: Dog = {
name: 'Шарик',
age: 5,
breed: 'Лабрадор',
isGoodBoy: true,
makeSound() {
console.log('Гав-гав!');
}
};
Множественное наследование интерфейсов:
interface HasId {
id: string;
}
interface HasTimestamp {
createdAt: Date;
updatedAt: Date;
}
interface User extends HasId, HasTimestamp {
name: string;
email: string;
}
// User должен иметь: id, createdAt, updatedAt, name, email
const user: User = {
id: '123',
name: 'Иван',
email: 'ivan@example.com',
createdAt: new Date(),
updatedAt: new Date()
};
Extend для типов
Расширение типов:
type BaseUser = {
id: string;
name: string;
};
// AdminUser имеет все свойства BaseUser плюс новые
type AdminUser = BaseUser & {
role: 'admin';
permissions: string[];
};
const admin: AdminUser = {
id: '1',
name: 'Администратор',
role: 'admin',
permissions: ['read', 'write', 'delete']
};
Extend в классах (наследование)
Классический паттерн наследования:
class Animal {
name: string;
constructor(name: string) {
this.name = name;
}
makeSound() {
console.log('Животное издаёт звук');
}
}
class Dog extends Animal {
breed: string;
constructor(name: string, breed: string) {
super(name); // Вызываем конструктор родителя
this.breed = breed;
}
// Переопределяем метод родителя (полиморфизм)
makeSound() {
console.log(`${this.name} лает: Гав-гав!`);
}
fetch() {
console.log(`${this.name} принёс мяч`);
}
}
const dog = new Dog('Шарик', 'Лабрадор');
dog.makeSound(); // Шарик лает: Гав-гав!
dog.fetch(); // Шарик принёс мяч
Extend для условных типов (Generic constraints)
Ограничение типа параметра:
// T должен иметь свойство 'id'
function getId<T extends { id: string }>(obj: T) {
return obj.id;
}
getId({ id: '123', name: 'Иван' }); // OK
getId({ name: 'Иван' }); // ОШИБКА: нет свойства id
// T должен быть подтипом массива
function getLength<T extends any[]>(arr: T) {
return arr.length;
}
getLength([1, 2, 3]); // OK
getLength('hello'); // ОШИБКА: string не массив
Extend с условными типами (Conditional Types)
Условная логика для типов:
// Если T — массив, вернуть тип элементов, иначе T
type Flatten<T> = T extends Array<infer U> ? U : T;
type Str = Flatten<string[]>; // string
type Num = Flatten<number>; // number
// Проверка: является ли T функцией
type IsFunction<T> = T extends (...args: any[]) => any ? true : false;
type A = IsFunction<() => void>; // true
type B = IsFunction<string>; // false
Практический пример: API Response типы
// Базовый тип ответа от API
interface ApiResponse<T> {
status: 'success' | 'error';
data?: T;
message: string;
}
// Специфичные типы ответов
interface User {
id: string;
name: string;
email: string;
}
interface UserResponse extends ApiResponse<User> {
// User response может иметь дополнительные поля
timestamp: Date;
}
// Функция работает с любым ApiResponse
function handleResponse<T>(response: ApiResponse<T>) {
if (response.status === 'success') {
console.log('Данные:', response.data);
} else {
console.log('Ошибка:', response.message);
}
}
// Использование
const userResponse: UserResponse = {
status: 'success',
data: {
id: '1',
name: 'Иван',
email: 'ivan@example.com'
},
message: 'OK',
timestamp: new Date()
};
handleResponse(userResponse);
Extend vs Intersection (&)
Интерфейсы используют extends:
interface A { x: number; }
interface B extends A { y: string; }
Типы используют пересечение (&):
type A = { x: number };
type B = A & { y: string };
Оба способа достигают похожего результата, но есть различия в ошибках и производительности.
Частая ошибка: Generic constraints
// НЕПРАВИЛЬНО: T может быть чем угодно
function printId<T>(obj: T) {
console.log(obj.id); // ОШИБКА: у T может не быть id
}
// ПРАВИЛЬНО: T должен иметь id
function printId<T extends { id: string }>(obj: T) {
console.log(obj.id); // OK
}
printId({ id: '123' }); // OK
printId({ name: 'Иван' }); // ОШИБКА: нет id
Ключевые выводы
- extend расширяет интерфейсы и типы — добавляет новые свойства
- Используй extends для наследования классов — переиспользование кода
- Generic constraints с extends — ограничение типов параметров
- Conditional types — условная логика для типов
- Помни про множественное наследование — интерфейсы могут расширять несколько других
Правильное использование extends критично для типобезопасности и переиспользования кода в TypeScript.