在 TypeScript 中,interface 和 type 都用于定义类型,但它们在设计目的、语法和功能上有明显差异。以下是它们的核心区别:
1. 基本概念
- 
**
interface**专门用于定义 对象类型 的形状(Object Shape),强调结构描述,适合描述类、对象、函数等结构。
typescripttypescript interface User { name: string; age: number; } - 
**
type**类型别名,可为任何类型(包括原始类型、联合类型、元组等)命名,用途更广泛。
typescripttypescript type ID = string | number; // 联合类型 type Point = [number, number]; // 元组 type Callback = () => void; // 函数类型 
2. 声明合并(Declaration Merging)
- 
**
interface**支持同名声明自动合并,适合扩展第三方类型或逐步定义类型。
kotlintypescript interface User { name: string; } interface User { age: number; } // 合并为 { name: string; age: number; } - 
**
type**同名重复声明会报错,无法合并。
initypescript type User = { name: string }; // ❌ Error: Duplicate identifier type User = { age: number }; 
3. 继承与扩展
- 
**
interface**使用
extends继承其他接口,语法更直观。phptypescript interface Animal { name: string; } interface Dog extends Animal { bark(): void; } - 
**
type**使用交叉类型
&实现类似继承的效果,更灵活。initypescript type Animal = { name: string }; type Dog = Animal & { bark(): void }; 
4. 适用场景
- 
**
interface专长**- 定义对象结构(如类、函数、对象)。
 - 需要声明合并(如扩展第三方类型)。
 - 类实现接口(
implements)。 
 - 
**
type专长**- 定义联合类型、元组、映射类型等复杂类型。
 - 使用条件类型(
extends ? :)、模板字面量类型等高级特性。 - 为其他类型提供别名(包括原始类型)。
 
initypescript type Status = "success" | "error"; // 字面量联合类型 type Keys = keyof User; // 映射类型 
5. 其他区别
| 特性 | interface | 
type | 
|---|---|---|
| 函数类型定义 | 支持对象语法和函数重载 | 只能直接定义函数签名 | 
| 动态属性 | 无法直接使用动态计算属性 | 可使用映射类型(in)动态生成属性 | 
| 类实现 | 支持 implements | 
若为对象类型,也能被类实现 | 
| 扩展性 | 更适合通过声明合并逐步扩展 | 扩展需重新定义或使用交叉类型 | 
映射类型(Mapped Types)
在 TypeScript 中,映射类型(Mapped Types) 是一种基于现有类型动态生成新类型的高级特性。它可以通过 in 关键字遍历一个联合类型的键集合,并为每个键生成新的属性类型。这是 type 独有的能力,interface 无法直接实现类似操作。
核心概念:用 in 动态生成属性
映射类型的基本语法为:
            
            
              ini
              
              
            
          
          typescript
type NewType = {
  [Key in Keys]: ValueType;
};
        - **
Key**:遍历的键(变量名,可以是任意标识符,如K)。 - **
Keys**:一个联合类型(例如"name" | "age"),表示要遍历的键集合。 - **
ValueType**:每个键对应的值的类型(可以是固定类型,或基于原类型的动态类型)。 
具体示例
1. 基本动态属性生成
假设有一个联合类型 Keys,基于它生成一个对象类型,每个属性的值类型为 string:
            
            
              ini
              
              
            
          
          typescript
type Keys = "name" | "age" | "email";
type DynamicObject = {
  [K in Keys]: string; // 遍历 Keys 中的每个键,值为 string
};
// 等价于:
type DynamicObject = {
  name: string;
  age: string;
  email: string;
};
        2. 基于现有类型转换
映射类型常与 keyof 结合,动态操作现有类型的所有属性:
            
            
              ini
              
              
            
          
          typescript
interface User {
  name: string;
  age: number;
  email: string;
}
// 将 User 的所有属性转换为可选属性
type OptionalUser = {
  [K in keyof User]?: User[K]; 
};
// 等价于:
type OptionalUser = {
  name?: string;
  age?: number;
  email?: string;
};
        3. 更复杂的类型操作
可以结合条件类型、模板字面量等特性,实现更动态的转换:
            
            
              typescript
              
              
            
          
          typescript
// 将 User 的所有属性名改为 `getXxx` 格式,且值为函数
type Getters = {
  [K in keyof User as `get${Capitalize<K>}`]: () => User[K];
};
// 等价于:
type Getters = {
  getName: () => string;
  getAge: () => number;
  getEmail: () => string;
};
        为什么 interface 无法实现?
interface 的设计初衷是声明对象的结构 ,而不是动态生成类型。它无法直接遍历联合类型或使用 in 动态生成属性。例如:
            
            
              csharp
              
              
            
          
          typescript
// ❌ 错误:interface 不支持映射类型语法
interface DynamicInterface {
  [K in "name" | "age"]: string;
}
        实际应用场景
- 
属性修饰符操作
快速生成
Readonly、Partial、Required等工具类型:initypescript type ReadonlyUser = Readonly<User>; // 所有属性变为只读 type PartialUser = Partial<User>; // 所有属性变为可选 - 
类型裁剪或转换
修改属性名或值的类型:
initypescript // 将 User 的所有属性值改为 boolean type BooleanUser = { [K in keyof User]: boolean; }; - 
筛选特定属性
结合条件类型过滤属性:
initypescript // 只保留 User 中的字符串类型属性 type StringProps = { [K in keyof User as User[K] extends string ? K : never]: User[K]; }; // 等价于 { name: string; email: string } 
总结
- **
type+ 映射类型**:通过in动态遍历联合类型的键集合,生成新的属性,适合复杂类型操作。 - **
interface**:静态定义对象结构,无法动态生成属性。 
当需要基于现有类型动态生成或修改属性时,映射类型是 type 的杀手级特性,而 interface 无法替代这一能力。
6. 错误提示
- **
interface**
错误提示更清晰,直接指出缺少或多余的属性。 - **
type**
复杂类型(如联合类型)的错误提示可能较冗长。 
7. 如何选择?
- 默认使用 
interface:定义对象结构、需要声明合并时。 - 使用 
type:需要联合类型、元组、高级类型操作时。 
两者在多数场景下可以互换,但理解差异能帮助写出更清晰的类型代码。
8. 总结
| 对比维度 | **interface** | 
**type** | 
|---|---|---|
| 基本用途 | 定义对象类型(类、函数、对象的结构) | 为任何类型命名(包括原始类型、联合类型、元组、函数等) | 
| 声明合并 | ✅ 支持同名合并(多次声明自动合并) | ❌ 禁止同名重复声明 | 
| 继承语法 | extends 关键字(直观继承接口) | 
交叉类型 &(通过 & 合并类型) | 
| 动态属性生成 | ❌ 不支持映射类型(无法用 in 动态生成属性) | 
✅ 支持映射类型(通过 in 遍历键集合生成属性) | 
| 适用场景 | 对象结构定义、声明合并、类实现(implements) | 
联合类型、元组、条件类型、模板字面量类型、复杂类型操作 | 
| 函数类型定义 | 支持对象语法和函数重载: { (x: number): number } | 
只能直接定义函数签名: type Fn = (x: number) => number | 
| 工具类型支持 | 需结合 extends 或工具类型间接操作 | 
直接支持 Partial、Readonly、Pick 等工具类型 | 
| 扩展性 | 适合逐步扩展(通过声明合并) | 需重新定义或交叉类型扩展 | 
| 错误提示 | 更清晰(直接指出属性缺失或冗余) | 复杂类型(如联合类型)可能提示冗长 | 
| 类实现 | 直接通过 implements 实现 | 
若为对象类型,也能被类实现 | 
| 示例 | interface User {<br> name: string;<br>} | 
type User = {<br> name: string;<br>} | 
| 映射类型示例 | ❌ 不可用 | ✅ type Optional<T> = {<br> [K in keyof T]?: T[K];<br>} |