TypeScript 面试必考:type 与 interface 到底有什么区别?

0 阅读7分钟

TypeScript 面试必考:type 与 interface 到底有什么区别?

"请你说说 TypeScript 中 typeinterface 的区别?"——这道题几乎出现在每一场前端面试中。很多人能说出一两点,但很难答全、答深。本文从面试角度系统梳理,帮你一次讲清楚。

目录


一、先看共同点:它们都能做什么?

在讨论区别之前,先明确 typeinterface共同能力,这是面试中容易被忽略的加分项。

1. 都可以描述对象结构

// interface 描述对象
interface User {
  name: string;
  age: number;
  avatarUrl: string;
}

// type 描述对象
type UserType = {
  name: string;
  age: number;
  avatarUrl: string;
};

// 用法完全一致
const u1: User = {
  name: 'zwq',
  age: 18,
  avatarUrl: 'https://zwq.ai/avatar.png',
};

const u2: UserType = {
  name: 'zwq',
  age: 18,
  avatarUrl: 'https://zwq.ai/avatar.png',
};

2. 都可以用于函数参数和返回值类型约束

function greet(user: User): string {
  return `Hello, ${user.name}`;
}

function greet2(user: UserType): string {
  return `Hello, ${user.name}`;
}

3. 都支持 readonly 修饰符

interface Config {
  readonly apiUrl: string;
}

type ConfigType = {
  readonly apiUrl: string;
};

面试话术typeinterface 在描述对象结构时,能力是完全重叠的。选择哪个更多是团队规范问题,而非功能限制。


二、核心区别逐条拆解

区别一:继承方式不同

这是面试中最常问的第一个点。

interface 使用 extends 继承:

interface Person {
  name: string;
}

interface Employee extends Person {
  job: string;
}

const e1: Employee = {
  name: '张三',
  job: '前端工程师',
};

type 使用交叉类型 & 实现组合:

type PersonType = {
  name: string;
};

type EmployeeType = PersonType & {
  job: string;
};

const e2: EmployeeType = {
  name: '李四',
  job: '后端工程师',
};

面试追问interface 能继承 type 吗? :可以!只要 type 描述的是对象结构,interface 就能 extends 它。反过来,type 也能用 & 组合 interface。两者在对象类型上是互通的。

interface Animal extends PersonType {
  species: string;
}

type WorkerType = EmployeeType & {
  company: string;
};
⚠️ 关键区分:extends& 在属性冲突时的行为差异

这是面试中拉开差距的深度追问点:

interface A { x: number }
interface B extends A { x: string } // ❌ 编译报错:类型不兼容

type C = A & { x: string }         // ✅ 不报错,但 x 的类型变为 never

面试要点extends严格的类型检查,属性冲突直接报错;&类型合并,冲突时会得到 never(编译通过但无法使用)。实际开发中 & 的这种"静默失败"更危险,因为它不会在编译期提醒你。


区别二:声明合并(Declaration Merging)

这是 interface 独有的能力,也是面试高频考点。

interface 可以重复声明,自动合并:

interface Animal {
  name: string;
}

// 再次声明同名 interface,属性会自动合并
interface Animal {
  age: number;
}

// 最终 Animal = { name: string; age: number }
const dog: Animal = {
  name: '旺财',
  age: 3,
};

type 不允许重复声明:

type AnimalType = {
  name: string;
};

// ❌ 编译报错:Duplicate identifier 'AnimalType'
type AnimalType = {
  age: number;
};

面试追问:声明合并有什么实际应用场景?

  1. 扩展第三方库类型:比如给 Window 对象添加自定义属性
  2. 模块化类型定义:不同文件中分批定义同一个接口
  3. 库的类型声明:很多 npm 包的 @types 定义大量依赖声明合并
// 扩展 Window 类型(实际开发高频场景)
declare global {
  interface Window {
    __APP_CONFIG__: {
      apiUrl: string;
      env: 'dev' | 'prod';
    };
  }
}

// 使用时就有类型提示了
const apiUrl = window.__APP_CONFIG__.apiUrl;

区别三:type 能表示非对象类型

这是 type 最大的优势——它的表达能力更广。

type 可以定义联合类型:

type ID = string | number;

// interface 没有联合类型的语法,只能描述对象结构

type 可以定义元组类型:

type Point = [number, number];

const p: Point = [10, 20];

type 可以定义基本类型别名:

type Status = 'loading' | 'success' | 'error';
type Age = number;
type Nullable<T> = T | null;

面试话术type 是"类型别名",可以为任何类型起别名;interface 专注于描述对象结构。当需要联合类型、元组、基本类型别名时,只能用 type


区别四:函数类型与索引签名

函数类型的写法

两者都能定义函数类型,但 type 的写法更简洁。

interface 定义函数类型(调用签名):

interface AddFn {
  (a: number, b: number): number;
}

const add1: AddFn = (x, y) => {
  return x + y;
};

type 定义函数类型:

type AddType = (a: number, b: number) => number;

const add2: AddType = (x, y) => {
  return x + y;
};

面试对比type 用箭头语法 => 直接定义,更符合我们对函数类型的直觉认知;interface 需要用调用签名的形式,写法更繁琐。实际开发中函数类型推荐用 type

索引签名

两者都支持索引签名,写法一致:

interface StringMap {
  [key: string]: string;
}

type StringMapType = {
  [key: string]: string;
};

注意interface 还支持构造签名new),这在定义类的构造函数类型时有用,但日常开发中较少用到。


三、一张表总结

特性interfacetype
描述对象结构
继承/组合extends(冲突时报错)&(冲突时 never
声明合并✅ 自动合并❌ 重复报错
联合类型string | number
元组类型[number, string]
基本类型别名type Age = number
函数类型✅ 调用签名✅ 箭头语法(更简洁)
索引签名
implements/extends✅ 类可实现✅(对象类型时)
映射类型/条件类型type 独有

四、面试标准回答模板

当面试官问"说说 typeinterface 的区别"时,建议按以下结构回答:

📋 点击展开完整回答模板

先说共同点:两者都可以描述对象结构,用于类型约束,能力在对象类型上是重叠的。

再说核心区别

  1. 继承方式不同——interfaceextendstype& 交叉类型。而且 extends 是严格检查,属性冲突直接报错;& 是合并,冲突时得到 never
  2. 声明合并——interface 支持同名自动合并,type 不允许重复声明。这在扩展第三方库类型时很有用
  3. 类型表达范围——type 可以定义联合类型、元组、基本类型别名,interface 只能描述对象结构
  4. 函数类型——都能定义,但 type 的箭头语法更简洁直观

最后说选择建议:描述对象结构优先用 interface(可扩展、可合并),需要联合类型或工具类型时用 type。团队统一规范最重要。


五、进阶:实际开发中怎么选?

场景推荐原因
定义 Props、State、API 响应interface可被 extends 扩展,支持声明合并
联合类型、字面量类型typeinterface 做不到
工具类型(PickOmit 等)type类型运算必须用 type
函数类型type写法更简洁
需要被 class implementsinterface语义更清晰

💡 真实项目中的经验法则:React 项目里,组件 Props 用 interface(方便扩展),工具函数的入参出参用 type(写法简洁)。两者混用是正常的,关键是团队统一。


六、面试加分项

如果你能主动提到以下几点,会是很好的加分项:

1. 声明合并的实际价值

扩展 WindowExpress.Request 等全局类型是声明合并最典型的实战场景。面试时举这个例子说明你有实际项目经验。

2. type 的映射类型和条件类型

这是 type 独有的高级能力,interface 无法实现:

// type 独有的映射类型
type Readonly<T> = { readonly [K in keyof T]: T[K] };
type Partial<T> = { [K in keyof T]?: T[K] };

// type 独有的条件类型
type IsString<T> = T extends string ? 'yes' : 'no';

// interface 无法做到
// interface Readonly<T> { readonly [K in keyof T]: T[K] } // ❌ 语法错误

3. 编译性能

interface 通常被认为在类型检查时有一定性能优势(声明式、支持延迟求值),但 TypeScript 官方未给出明确对比结论。实际差异在多数项目中可忽略不计,不必过度纠结。

4. 社区趋势

React 社区倾向用 interface 定义 Props(Airbnb、Google 的 TS 规范都是如此),TypeScript 工具库倾向用 type。了解这些有助于你在面试中展现对社区生态的关注。


📌 一句话总结interface 是"对象的契约",type 是"类型的别名"。对象结构用 interface,类型运算用 type,面试时把这个逻辑讲清楚就稳了。


你在面试中被问到过这个问题吗?你平时写 TypeScript 更习惯用 type 还是 interface?欢迎在评论区聊聊你的选择和理由 👇