Комментарии (1)
Ответ сгенерирован нейросетью и может содержать ошибки
Что такое пересечение типов
Пересечение типов (type intersection) — это TypeScript операция, которая объединяет несколько типов в один, содержащий все свойства и методы каждого из них. Обозначается символом &.
Основное понятие
Пересечение типов создаёт новый тип, который одновременно является:
- Первым типом
- Вторым типом
- Третьим типом
- И так далее
type A = {
name: string;
};
type B = {
age: number;
};
// Пересечение типов A и B
type Person = A & B;
// Эквивалентно:
type Person = {
name: string;
age: number;
};
const person: Person = {
name: "Иван",
age: 30
};
Отличие от Union Types
Union types (|) — это логическое ИЛИ:
type A = { x: number };
type B = { y: string };
type Union = A | B; // либо A, либо B (но не оба)
const obj1: Union = { x: 5 }; // OK
const obj2: Union = { y: "hi" }; // OK
const obj3: Union = { x: 5, y: "hi" }; // OK (но избыточно)
Intersection types (&) — это логическое И:
type A = { x: number };
type B = { y: string };
type Intersection = A & B; // одновременно и A, и B
const obj: Intersection = { x: 5, y: "hi" }; // OK
// Оба свойства ОБЯЗАТЕЛЬНЫ
Практические примеры
// Пример 1: Расширение интерфейсов
type Identifiable = {
id: number;
};
type Timestamped = {
createdAt: Date;
updatedAt: Date;
};
type User = Identifiable & Timestamped & {
name: string;
email: string;
};
const user: User = {
id: 1,
createdAt: new Date(),
updatedAt: new Date(),
name: "Мария",
email: "maria@example.com"
};
Пересечение интерфейсов с interface
Те же операции работают с interface (хотя для них есть наследование):
interface HasId {
id: number;
}
interface HasName {
name: string;
}
interface HasTimestamp {
timestamp: Date;
}
type Document = HasId & HasName & HasTimestamp;
const doc: Document = {
id: 1,
name: "Report",
timestamp: new Date()
};
Но с интерфейсами лучше использовать наследование:
interface Document extends HasId, HasName, HasTimestamp {
// дополнительные свойства
}
Пересечение примитивных типов
Пересечение примитивов создаёт never (невозможный тип):
type Impossible = string & number; // тип never
const value: Impossible = ???; // ошибка: невозможно присвоить
Так как значение не может быть одновременно строкой И числом.
Сложные примеры
// Пример: Mixins
type Loggable = {
log: () => void;
};
type Serializable = {
serialize: () => string;
};
type Observable = {
subscribe: (callback: () => void) => void;
};
type FullFeatured = Loggable & Serializable & Observable;
const obj: FullFeatured = {
log() { console.log("log"); },
serialize() { return JSON.stringify({}); },
subscribe(cb) { cb(); }
};
Пересечение объектов с конфликтом
Если типы имеют одинаковое свойство с разными типами:
type A = { prop: string };
type B = { prop: number };
type Conflict = A & B; // prop: string & number = never
// Это создаёт конфликт
const obj: Conflict = {
prop: ??? // ошибка: ни string, ни number не подходят
};
Практическое применение: Декораторы и HOC
// Props базового компонента
type BaseProps = {
className?: string;
style?: React.CSSProperties;
};
// Props с функциональностью
type WithLogging = {
onLog: (message: string) => void;
};
type WithValidation = {
validate: () => boolean;
};
// Комбинированный тип для компонента
type EnhancedComponentProps = BaseProps & WithLogging & WithValidation;
function MyComponent(props: EnhancedComponentProps) {
return <div className={props.className}>content</div>;
}
Generic пересечения
function merge<T, U>(obj1: T, obj2: U): T & U {
return { ...obj1, ...obj2 } as T & U;
}
const a = { x: 1 };
const b = { y: "hello" };
const merged = merge(a, b);
// merged имеет тип: { x: number } & { y: string }
console.log(merged.x); // 1
console.log(merged.y); // "hello"
Отличие от наследования
// Через наследование
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Через пересечение типов
type Animal = { name: string };
type Dog = Animal & { breed: string };
// Результат один и тот же, но пересечение более гибкое
Лучшие практики
- Используйте для комбинирования независимых функциональностей
type Component = Renderable & Clickable & Hoverable;
- Предпочитайте наследование для иерархий
interface Parent { }
interface Child extends Parent { }
-
Избегайте конфликтов типов — проверяйте совместимость
-
Документируйте сложные пересечения — может быть не очевидно
Итог: пересечение типов — это мощный инструмент для комбинирования типов и создания сложных структур данных в TypeScript.