一、接口继承:像叠乐高积木般的类型拓展

在TypeScript中,接口继承通过extends关键字实现(类似C#/Java中的接口继承)。假设我们设计一个电商系统的用户体系:

// 技术栈:TypeScript 4.9+
interface BaseUser {
  id: string;
  createdTime: Date;
  getAuthToken(): string; 
}

// 多层继承示例
interface VIPUser extends BaseUser {
  vipLevel: number;
  /** 专属优惠权益 */
  specialDiscount(originalPrice: number): number; 
}

// 多继承示例(逗号分隔)
interface AdminUser extends BaseUser, VIPUser {
  permissionList: string[];
  revokePermission(userId: string): void;
}

// 实现多重接口的类
class UserManager implements AdminUser {
  id = "U20230428001";
  createdTime = new Date();
  vipLevel = 3;
  permissionList = ["user.delete", "order.modify"];

  getAuthToken() {
    return Buffer.from(this.id).toString('base64');
  }

  specialDiscount(price: number) {
    return this.vipLevel > 2 ? price * 0.6 : price;
  }

  revokePermission(userId: string) {
    console.log(`Revoking ${userId}'s permissions`);
  }
}

应用场景说明:当系统需要多种权限级别时,分层式接口可以保持核心字段的一致性。比如游戏系统中的普通玩家、公会会长、管理员的三层结构。


二、混合类型:用接口实现瑞士军刀般的多态性

通过&交叉类型实现混入效果,这在可复用UI组件中极为常见:

// 技术栈:TypeScript 4.9+
interface Clickable {
  onClick: (event: MouseEvent) => void;
}

interface Draggable {
  dragStartPos: { x: number, y: number };
  onDragStart(): void;
}

// 混合接口类型
type HybridComponent = Clickable & Draggable & {
  containerId: string;
  /** 用于调试的DOM路径 */
  debugSelector(): string;
};

// 混合类型应用
const calendarEvent: HybridComponent = {
  containerId: "#event-123",
  dragStartPos: { x: 0, y: 0 },
  
  onClick(e) {
    console.log(`点击坐标:${e.clientX},${e.clientY}`);
  },
  
  onDragStart() {
    this.dragStartPos = { x: Math.random()*100, y: Math.random()*100 };
  },
  
  debugSelector() {
    return `div${this.containerId} > .event-wrapper`;
  }
};

技术对比:与类继承相比,混合类型更适合临时组合功能。例如在图表库中,LineChart & TooltipSupport & Exportable的组合比多层继承更灵活。


三、类与接口的共生关系:实现契约与扩展的双向奔赴

当类实现接口时,编译器会严格校验形态,这在服务层抽象中尤为关键:

// 技术栈:TypeScript 4.9+
interface CacheStore<T> {
  set(key: string, value: T, ttl: number): boolean;
  get(key: string): T | null;
  delete(key: string): void;
}

// 抽象类与接口协同
abstract class BaseCache implements CacheStore<any> {
  abstract set(key: string, value: any, ttl: number): boolean;
  
  get(key: string) {
    console.log(`Fetching ${key} from cache`);
    return null; // 模拟实现
  }
  
  delete(key: string) {
    console.log(`Key ${key} removed`);
  }
}

// 具体实现
class RedisCache extends BaseCache {
  private client = connectRedis();
  
  set(key: string, value: any, ttl = 300) {
    return this.client.setEx(key, ttl, JSON.stringify(value));
  }

  // 扩展原生方法
  scanPattern(pattern: string) {
    return this.client.scan(pattern);
  }
}

注意事项:当接口定义可选属性时,实现类需要明确处理undefined值。例如支付网关接口中的retryCount?: number字段需要有默认值逻辑。


四、交叉应用与边界突破

在状态管理库中使用接口组合:

interface Pagination {
  currentPage: number;
  pageSize: number;
}

interface FilterCondition {
  keywords?: string;
  minPrice?: number;
}

// 分页查询请求类型
type ListRequest = Pagination & FilterCondition & {
  /** 是否返回缩略图 */
  includeThumbnail: boolean;
};

function fetchProducts(params: ListRequest) {
  const query = new URLSearchParams({
    page: params.currentPage.toString(),
    size: params.pageSize.toString(),
    ...(params.keywords && { q: params.keywords })
  });
  // 发送请求...
}

性能提醒:过度使用交叉类型会增加类型检查耗时。建议单个接口的交叉项不超过5个,复杂场景改用继承体系。


五、实战场景与架构选择

场景1:插件系统开发

采用接口继承保证插件契约:

interface CorePlugin {
  version: string;
  init(config: object): void;
}

interface UIPlugin extends CorePlugin {
  render(root: HTMLElement): void;
  onUnmount?: () => void;
}

场景2:微服务通信规范

RPC接口标准化:

interface RpcPayload {
  traceId: string;
  timestamp: number;
}

interface UserService extends RpcPayload {
  getProfile(userId: string): Promise<User>;
  searchUsers(condition: FilterCondition): Promise<User[]>;
}

选型决策树

  • 需要严格契约 → 类实现接口
  • 动态功能组合 → 混合类型
  • 领域模型扩展 → 接口继承

六、技术总结与最佳实践

优势亮点

  • 接口继承的显式继承链有助于代码导航
  • 混合类型突破单继承限制(Vue3 Composition API的ref()reactive()组合即为典型)
  • 类接口实现强制约束,降低集成成本

避坑指南

  1. 循环引用问题:当InterfaceA extends InterfaceBInterfaceB extends InterfaceA时引发编译错误
  2. 类型覆盖冲突:交叉类型中出现同名不同类型字段时(如{ id: string } & { id: number })会得到never类型
  3. 运行时校验缺失:接口仅在编译时存在,需搭配io-ts等库实现运行时类型校验

未来趋势

随着TypeScript 5.0引入装饰器元数据,接口与装饰器的结合将更紧密。例如通过@implement(StorageInterface)自动生成校验代码。