在 TypeScript 中,interface type 都用于定义类型,但两者在语法特性、使用场景和扩展能力上有显著差异。接下来我会从五个方面配合案例解读:

1. 声明合并

  • Interface:支持声明合并。多次定义同名接口时,TypeScript 会自动合并它们的成员。
    interface Person { name: string }
    interface Person { age: number }
    // 合并后:{ name: string; age: number }
  • Type:不允许重复声明同名类型,会直接报错。
    type Person = { name: string };
    type Person = { age: number }; // Error: 重复标识符 

    应用场景:如上例所示,当需要扩展第三方库类型或模块化定义对象结构时,interface 的声明合并特性非常有用。例如,为现有类型添加自定义属性。

2. 扩展与组合方式

  • Interface:使用 extends 关键字扩展其他接口或类型,甚至类。
    interface Parent {
      id: number;      // 父接口的必选属性
      name: string;
    }
    
    interface Child extends Parent {
      age: number;     // 子接口新增的属性
    }
    
    // 实现子接口的对象必须包含 Parent + Child 所有必选属性
    const person: Child = {
      id: 1,          // ✔ 必须实现父接口属性
      name: "Alice",  // ✔
      age: 30         // ✔ 子接口新增属性
    };
  • Type:通过交叉类型(&)组合多个类型,但无法直接扩展类。
    type Animal = { name: string };
    type Dog = Animal & { breed: string };

    需要注意:

  • interface 继承时当子接口通过 extends 继承父接口时,子接口的实现必须同时满足父接口和子接口的所有必选属性。且可以重新声明父接口的属性,但新定义的属性类型必须是父接口类型的 子类型或相同类型,否则会导致类型冲突。
    interface Parent {
      role: string;
    }
    
    interface Child extends Parent {
      role: "admin" | "user";  // ✔ 合法:字面量类型是 string 的子类型
    }
    
    
    interface Child extends Parent {
      role: number;  // ❌ 错误:number 无法赋值给 string
    }
  • type 交叉类型会合并同名属性,可能导致逻辑错误(如 string & number 为 never)。
    interface A { prop: string; }
    interface B extends A { prop: number; } // Error: 类型冲突 
    
    type C = { prop: string; } & { prop: number; }; // prop: never 

 

3. 实现与联合类型

  • Type:更擅长定义复杂类型组合,如联合类型(|)和元组,
    // 联合类型(仅 type 支持)
    type Result = string | number;
    function print(result: Result) { /* ... */ } 
    
    // 元组(仅 type 支持)
    type Coordinates = [number, number]; 
    
    

    场景对比

  • interface 无法直接定义联合类型,但可通过组合多个接口实现:
    interface Cat { purrs: boolean; }
    interface Dog { barks: boolean; }
    type Pet = Cat | Dog; 

 

 4. 类实现(Class Implements)

类可通过 implements 实现 interface type,但无法实现联合类型的 type

interface Person { name: string; }
class Student implements Person { name = "John"; } // 合法 

type PersonType = { name: string; };
class Teacher implements PersonType { name = "Jane"; } // 合法 

type UnionPerson = { name: string; } | { age: number; };
class Employee implements UnionPerson { /* Error: 无法实现联合类型 */ } 

这里怕读者不知道什么是implements 关键字,简单的解释一下:

interface 接口或 type 别名,可以用对象的形式,为 class 指定一组检查条件。然后,使用 implements 关键字,表示当前满足这些外部型条件的限制。

implements 的作用

1. 强制类型检查

  • 编译器验证:TypeScript 会在编译时检查类是否完整实现了接口的所有 必选属性/方法(包括类型一致性)。
  • 错误提前暴露:若类与接口的成员不匹配(缺少属性、类型不符),编译阶段立即报错,避免运行时潜在问题。

2. 代码约定与文档化

  • 明确契约:通过接口定义类必须具备的能力,例如 Country 必须包含 name 和 capital
  • 提高可读性:开发者一眼可知类的核心功能,例如 MyCountry 需遵循 Country 的规范。
interface Country {
  name:string;
  capital:string;
}
// 或者
type Country = {
  name:string;
  capital:string;
}
class MyCountry implements Country {
  name = '';
  capital = '';
}

上面示例中,interfacetype都可以定义一个对象型。MyCountry使用implements关键字,表示该的实例对象满足这个外部型。

 

5. 支持的类型范围

  • Interface:主要用于定义对象结构,支持可选属性、只读属性和函数类型,但无法直接定义原始类型、元组或联合类型。
    interface User {
      name: string;
      age?: number; // 可选属性
      readonly id: string; // 只读属性
    }
  • Type:更灵活,可定义原始类型、元组、联合类型、映射类型等。
    type ID = string | number; // 联合类型
    type Point = [number, number]; // 元组
    type Primitive = string; // 原始类型别名

    type 在定义函数类型和工具类型时更灵活。

    // 函数类型(两种写法)
    interface AddFunc { (a: number, b: number): number; }
    type AddType = (a: number, b: number) => number; 
    
    // 条件类型(仅 type 支持)
    type IsString<T> = T extends string ? true : false; 

    场景建议

  • 使用 type 定义函数重载或复杂泛型逻辑。
  • 使用 interface 定义对象方法的结构(如类的方法签名)。

总结,概括整篇文章 ----- 何时选择 interface 或 type?

场景 推荐使用 原因 示例
定义对象结构并需要扩展 interface 支持声明合并和直观的继承逻辑

公共 API、第三方库类型扩展 

联合类型、元组、工具类型 type 支持复杂类型操作和组合

联合类型、条件类型 

类实现或方法签名 interface 与类继承机制更契合 类方法契约 
函数类型或类型操作 type 语法简洁,支持高级类型操作 函数重载、泛型工具 
  • 优先 interface:面向对象设计、需要动态扩展或团队协作时。
  • 优先 type:处理复杂类型逻辑、联合/交叉类型或工具类型时。
  • 混合使用:例如用 interface 定义对象结构,用 type 定义工具类型 .
Logo

有“AI”的1024 = 2048,欢迎大家加入2048 AI社区

更多推荐