如何区分 TypeScript 中的自定义类型和接口?

解释 TypeScript 中 type 和 interface 的区别及其使用场景。

TypeScript 中等 类型系统 接口 类型别名

在 TypeScript 中, 类型别名(type) 和 接口(interface) 是定义类型的两种常用工具。 两者有相似之处, 但区别主要表现在功能范围 、扩展性 、合并性和高级类型支持方面。

1. 定义 Type Aliases(类型别名)

使用 type 关键字为 任意类型 创建新名称, 包括基本类型 、联合类型 、交叉类型 、映射类型等。

示例代码

// 定义类型别名
type StringOrNumber = string | number; // 联合类型
type Point = { x: number; y: number; }; // 对象类型
type Callback = (data: string) => void; // 函数类型

类型别名适用于描述复杂或组合的类型结构, 如在泛型编程和联合类型场景中更灵活。

2. 定义 Interfaces(接口)

使用 interface 关键字专门描述 对象结构,强制其形状属性和方法。

示例代码

interface Person {
  name: string;
  age?: number; // 可选属性
  sayHello(greeting: string): void; // 方法签名
}
let user: Person = {
  name: "Alice",
  sayHello(greeting) {
    console.log(greeting + this.name);
  }
};

接口常用于类实现和对象约束场景,如描述 API 响应的形状或类接口契约。

3. 区别对比

两者主要差异在以下方面:

  1. 功能范围不同 :
    • 类型别名支持 任意类型(如联合 | 、元组 、泛型等);例如 type Colors = " red " | " green "
    • 接口仅支持 对象或函数签名;侧重于对象属性的描述。
  2. 扩展性方式不同 :
    • 接口 使用 extends 语法支持继承;能直接通过基接口扩展新属性。
       interface Student extends Person {
         studentId: number;
       }
      
    • 类型别名通过 交叉类型 ` & ` 间接实现扩展;无原生 extends 支持。
       type ExtendedPerson = Person & {
         nickname: string;
       };
      
  3. 声明合并性不同 :
    • 接口允许多次声明同名接口合并;编译器自动合并所有属性定义。
       interface User { name: string; }
       interface User { age: number; } // 自动合并为{name,age}
      
    • 类型别名 不支持合并;同名定义会报冲突错误,只能唯一重定义一次。
  4. 高级类型能力不同 :
    • 类型别名支持映射类型(mapped types)、 条件类型(conditional types)等高级类型;例如 ` type Optional = { [K in keyof T]? : T[K] } `适用于类型变换优化工具链逻辑。
    • 接口无此能力,不适用于复杂泛型转换。

4. 最佳实践建议

根据项目需求选择:

  • 优先用 接口(interface) 表达对象形状,便于面向类设计和可读性维护(支持声明合并及显式继承)。
  • 需定义联合类型 、元组类型 、映射泛型等高阶功能时, 使用 类型别名(type)实现灵活性。避免误用于对象替代场景。