如何区分 TypeScript 中的自定义类型和接口?
解释 TypeScript 中 type 和 interface 的区别及其使用场景。
在 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. 区别对比
两者主要差异在以下方面:
- 功能范围不同 :
- 类型别名支持 任意类型(如联合
|
、元组 、泛型等);例如type Colors = " red " | " green "
。 - 接口仅支持 对象或函数签名;侧重于对象属性的描述。
- 类型别名支持 任意类型(如联合
- 扩展性方式不同 :
- 接口 使用
extends
语法支持继承;能直接通过基接口扩展新属性。interface Student extends Person { studentId: number; }
- 类型别名通过 交叉类型 ` & ` 间接实现扩展;无原生
extends
支持。type ExtendedPerson = Person & { nickname: string; };
- 接口 使用
- 声明合并性不同 :
- 接口允许多次声明同名接口合并;编译器自动合并所有属性定义。
interface User { name: string; } interface User { age: number; } // 自动合并为{name,age}
- 类型别名 不支持合并;同名定义会报冲突错误,只能唯一重定义一次。
- 接口允许多次声明同名接口合并;编译器自动合并所有属性定义。
- 高级类型能力不同 :
- 类型别名支持映射类型(mapped types)、 条件类型(conditional types)等高级类型;例如 ` type Optional
= { [K in keyof T]? : T[K] } `适用于类型变换优化工具链逻辑。 - 接口无此能力,不适用于复杂泛型转换。
- 类型别名支持映射类型(mapped types)、 条件类型(conditional types)等高级类型;例如 ` type Optional
4. 最佳实践建议
根据项目需求选择:
- 优先用
接口
(interface) 表达对象形状,便于面向类设计和可读性维护(支持声明合并及显式继承)。 - 需定义联合类型 、元组类型 、映射泛型等高阶功能时, 使用
类型别名
(type)实现灵活性。避免误用于对象替代场景。