Intersection Types
Intersection Types (
A & B) — тип, объединяющий свойства нескольких типов: значение должно удовлетворять всем типам одновременно, то есть содержать все поля каждого из них.
Зачем нужно
Intersection типы позволяют комбинировать независимые типы без наследования. Это основной механизм создания «составных» типов из отдельных частей (mixins, merge объектов, аугментация типов).
Где используется
- Mixins и композиция поведения
- Объединение базового типа с дополнительными свойствами (
WithId,WithTimestamps) - Функции, принимающие объекты с несколькими контрактами
- Branded Types (
string & { _brand: "..." }) - Тип результата
Object.assignи spread-операций
Основной контент
Базовый синтаксис
type Named = { name: string };
type Aged = { age: number };
type Person = Named & Aged;
const alice: Person = { name: "Alice", age: 30 }; // OK
const bob: Person = { name: "Bob" }; // Error — нет age
Паттерн: добавление мета-полей
type WithId<T> = T & { id: string };
type WithTimestamps<T> = T & { createdAt: Date; updatedAt: Date };
interface UserInput {
name: string;
email: string;
}
type User = WithId<WithTimestamps<UserInput>>;
// { name: string; email: string; id: string; createdAt: Date; updatedAt: Date }
function createUser(input: UserInput): User {
return {
...input,
id: crypto.randomUUID,
createdAt: new Date,
updatedAt: new Date,
};
}
Intersection примитивов — never
type Impossible = string & number; // never
// Применяется в Branded Types:
type UserId = string & { readonly _brand: "UserId" };
Intersection vs extends интерфейсов
// При конфликте свойств:
interface A { value: string }
interface B { value: number }
// interface C extends A, B {} // Error — конфликт типа value
type C = A & B; // OK синтаксически, но value: string & number = never
Generic merge-функция
function merge<T, U>(a: T, b: U): T & U {
return { ...a, ...b } as T & U;
}
const merged = merge({ name: "Alice" }, { age: 30 });
// { name: string; age: number }
console.log(merged.name); // OK
console.log(merged.age); // OK
Intersection интерфейсов-контрактов
interface Serializable {
serialize: string;
}
interface Persistable {
save: Promise<void>;
}
type StorableEntity = Serializable & Persistable;
class Order implements Serializable, Persistable {
serialize { return JSON.stringify(this); }
async save { /* ... */ }
}
const order: StorableEntity = new Order();
Частые ошибки
- Путать
&и|—&требует всего из обоих типов (intersection),|принимает любой из них (union). - Intersection примитивов даёт
never—string & number=never; используйте|для «одно из». - Конфликт полей при intersection —
(A & B).fieldгде типы поля несовместимы =neverдля этого поля. - Мутировать merged-объект —
as T & Uэто cast, не глубокое копирование; побочные эффекты остаются.
Связанные темы
- Union Types
- interface -- объявление и использование
- Расширение интерфейсов -- extends
- Branded Types
- _MOC TypeScript