跳到主要内容

interfacetype 有什么区别?

下文默认基于 TypeScript 5.x,并假设开启 strict: true

面试速答(30 秒版 TL;DR)

  • interfacetype 都能描述“值的形状”,比如对象结构、函数签名。
  • 真正差别不在“谁更高级”,而在表达能力和扩展方式
    • interface 更适合描述对象契约、类实现、库的可扩展 API。
    • type 更适合做联合类型、交叉类型、条件类型、映射类型这类“类型计算”。
  • 一个高频结论:
    • 想表达“一个对象长什么样”,interface 通常更直观;
    • 想表达“把几个类型拼装、变换、过滤”,type 更合适。
  • 面试里不要答成“完全等价”。它们有重叠,但不完全重叠。

1. 先看共同点:都能描述对象和函数

interface UserByInterface {
id: number;
name: string;
}

type UserByType = {
id: number;
name: string;
};

interface FnByInterface {
(value: string): number;
}

type FnByType = (value: string) => number;

所以第一句话应该先说清楚:

  • 在“描述普通对象结构”这件事上,它们大量重叠;
  • 差异主要体现在“还能不能继续做更复杂的类型表达”。

2. 核心区别:type 能做类型运算,interface 更偏契约声明

2.1 type 可以直接表示联合、交叉、原始类型、元组

type Status = "idle" | "loading" | "success" | "error";
type Id = string | number;
type Pair = [string, number];
type WithTime = { createdAt: Date } & { updatedAt: Date };

这些写法 interface 做不到。

所以面试里一个很稳的答法是:

  • type 不只是“对象别名”;
  • 它本质上是给任意类型表达式起名字。

2.2 interface 更强调“对象世界里的扩展和约束”

interface Animal {
name: string;
}

interface Dog extends Animal {
bark(): void;
}

class Husky implements Dog {
constructor(public name: string) {}

bark() {
console.log("wang");
}
}

这类“接口扩展 + 类实现”的语义,用 interface 可读性通常更强。

3. 一个非常高频的区别:声明合并

interface 支持 declaration merging,type 不支持。

interface RequestConfig {
url: string;
}

interface RequestConfig {
timeout?: number;
}

const config: RequestConfig = {
url: "/api/user",
timeout: 3000,
};

最终 RequestConfig 会被合并成:

{
url: string;
timeout?: number;
}

但下面这种写法会报错:

type RequestConfigType = {
url: string;
};

type RequestConfigType = {
timeout?: number;
};

这也是为什么:

  • 写库类型声明;
  • 扩展全局对象;
  • 给第三方库做补充声明;

很多场景会优先看到 interface

4. extends& 看起来像,语义并不完全一样

4.1 interface extends

interface A {
name: string;
}

interface B extends A {
age: number;
}

更像“基于已有契约继续扩展”。

4.2 type 用交叉类型 &

type A = {
name: string;
};

type B = A & {
age: number;
};

更像“把多个类型结果组合起来”。

工程上常见区别是:

  • extends 偏声明式、面向对象建模;
  • & 偏类型运算、组合式建模。

5. 什么时候优先用 interface

下面这些场景,interface 往往更自然:

  • 定义组件 props、接口返回对象、领域模型对象;
  • 给 class 做 implements
  • 需要声明合并;
  • 希望团队把它理解成“可扩展的对象契约”。

示例:

interface ButtonProps {
type?: "primary" | "default";
disabled?: boolean;
onClick?: () => void;
}

6. 什么时候优先用 type

下面这些场景,type 基本更合适:

  • 联合类型;
  • 交叉类型;
  • 条件类型;
  • 映射类型;
  • 元组;
  • 给一个复杂类型表达式起别名。
type ApiState<T> =
| { status: "loading" }
| { status: "success"; data: T }
| { status: "error"; message: string };

这类写法如果硬换成 interface,通常会很别扭。

7. 高频面试题标准答法

7.1 interface 能不能替代 type

不能完全替代。

因为 interface 不能直接表示:

  • 联合类型;
  • 条件类型;
  • 元组;
  • 原始类型别名。

7.2 type 能不能替代 interface

很多“对象结构描述”可以替代,但有两个常见缺口:

  • 没有声明合并;
  • 在“接口契约”语义上不如 interface 直观。

7.3 团队里到底怎么选

比较稳的工程规则是:

  • 对象契约优先 interface
  • 类型运算优先 type
  • 不要为了统一而牺牲表达力。

8. 常见误区

  • 误区 1:认为 interfacetype 更“面向对象”,所以任何地方都该用它。
    • 事实是 TypeScript 的很多高级能力都建立在 type 上。
  • 误区 2:认为 type 只是 interface 的别名。
    • 不对,type 的表达范围明显更大。
  • 误区 3:把 extends& 当成完全等价。
    • 它们很多时候结果接近,但设计意图不同。

速记要点

  • interface 侧重对象契约、扩展、实现、声明合并。
  • type 侧重类型表达式和类型运算。
  • 描述对象时两者有重叠;做联合、条件、映射时优先 type