深圳雪聪网
我的

typescript 交叉类型的实现示例

2026-03-27 12:55:01 浏览次数:0
详细信息

& 运算符将多个类型合并成一个新类型。下面是几种常见的实现示例:

1. 基本对象类型合并

interface Person {
  name: string;
  age: number;
}

interface Employee {
  company: string;
  id: number;
}

// 交叉类型:同时具有 Person 和 Employee 的属性
type EmployeePerson = Person & Employee;

const john: EmployeePerson = {
  name: "John",
  age: 30,
  company: "Tech Corp",
  id: 1001
};

// 缺少任何属性都会报错
const invalid: EmployeePerson = {
  name: "Alice",
  age: 25
  // 错误:缺少 company 和 id 属性
};

2. 方法合并

interface Logger {
  log(message: string): void;
}

interface Formatter {
  format(data: any): string;
}

// 交叉类型:同时具有两个接口的方法
type LoggerFormatter = Logger & Formatter;

const loggerFormatter: LoggerFormatter = {
  log(message: string) {
    console.log(message);
  },
  format(data: any): string {
    return JSON.stringify(data);
  }
};

3. 与类型别名结合

type Admin = {
  adminLevel: number;
  permissions: string[];
};

type User = {
  id: string;
  email: string;
};

// 交叉类型创建管理员用户
type AdminUser = User & Admin;

const admin: AdminUser = {
  id: "user-123",
  email: "admin@example.com",
  adminLevel: 3,
  permissions: ["read", "write", "delete"]
};

4. 使用泛型的交叉类型

function merge<T, U>(obj1: T, obj2: U): T & U {
  return { ...obj1, ...obj2 };
}

const obj1 = { name: "Alice" };
const obj2 = { age: 30 };
const merged = merge(obj1, obj2); // 类型为 { name: string } & { age: number }

console.log(merged.name); // "Alice"
console.log(merged.age);  // 30

5. 处理冲突类型

interface A {
  value: number;
  common: string;
}

interface B {
  value: string; // 与 A 的 value 类型冲突
  common: string;
}

// 冲突的属性会变成 never 类型
type Conflict = A & B;

// 以下代码会报错,因为 value 的类型是 never
const obj: Conflict = {
  value: "test", // 错误:不能将 string 赋值给 never
  common: "hello"
};

6. 实用场景示例

// 1. 构建复杂组件 Props
interface BaseProps {
  className?: string;
  id?: string;
}

interface ButtonProps {
  onClick: () => void;
  disabled?: boolean;
}

type ComponentProps = BaseProps & ButtonProps;

// 2. Mixin 模式
class Disposable {
  isDisposed: boolean = false;
  dispose() {
    this.isDisposed = true;
  }
}

class Activatable {
  isActive: boolean = false;
  activate() {
    this.isActive = true;
  }
  deactivate() {
    this.isActive = false;
  }
}

// 使用交叉类型表示合并后的类型
type SmartObject = Disposable & Activatable;

function createSmartObject(): SmartObject {
  // 创建对象并组合两个类的功能
  return Object.assign(
    {},
    new Disposable(),
    new Activatable()
  );
}

const smartObj = createSmartObject();
smartObj.activate();
smartObj.dispose();

7. 使用条件类型优化

// 过滤掉某些属性
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };

// 确保两个类型互斥
type XOR<T, U> = (T | U) extends object
  ? (Without<T, U> & U) | (Without<U, T> & T)
  : T | U;

// 使用示例:要么有 a,要么有 b,但不能同时有
type Options = XOR<{ a: string }, { b: number }>;

const opt1: Options = { a: "test" };    // ✓
const opt2: Options = { b: 123 };       // ✓
const opt3: Options = { a: "test", b: 123 }; // ✗ 错误

注意事项

同名属性冲突:如果同名属性的类型不一致,交叉后会变成 never 类型 类型推断:交叉类型的推断是深度合并,不仅仅是浅层合并 编译时特性:交叉类型只在编译时存在,运行时没有对应的 JavaScript 代码 性能考虑:过度复杂的交叉类型可能会影响编译性能

交叉类型在构建复杂的类型系统、实现 Mixin 模式、以及组合多个类型约束时非常有用。

相关推荐