TypeScript 中 type 和 interface 的区别

1、interface

interface(接口) 是 TS 设计出来用于定义对象类型的,可以对对象的形状进行描述。

ts 复制代码
// 定义
interface Person {
  name: string
  age: number
}

// 使用
const person: Person = {
  name: 'lin',
  age: 18,
};

2、type

type (类型别名),顾名思义,类型别名只是给类型起一个新名字。

它并不是一个类型,只是一个别名而已。

ts 复制代码
// 定义
type Person = {
  name: string;
  age: number;
}

// 使用
const person: Person = {
  name: 'lin',
  age: 18,
};

3、两者相同点

3.1、都可以定义一个对象或函数

定义对象上面已经有例子了,我们来看一下如何定义函数。

ts 复制代码
// 使用 type 定义
type addType = (num1: number, num2: number) => number;

// 使用 interface 定义
interface addType {
  (num1: number, num2: number): number;
}

// 上面这两种写法都可以定义函数类型,效果是一样的

// 使用
const add: addType = (num1, num2) => {
  return num1 + num2;
};

3.2、都允许继承 extends(也可以叫拓展)

  • interface 可以使用 extends 关键字来扩展其他接口,实现接口的继承。
  • type 使用交叉类型(&)来合并多个类型,实现类型的组合。

我们定义一个 Person 类型和 Student 类型,Student 继承自 Person,可以有下面四种方式:

interface 继承 interface

ts 复制代码
interface Person { 
  name: string;
}

interface Student extends Person { 
  grade: number;
}

// 使用
const person: Student = {
  name: 'lin',
  grade: 100,
};

type 继承 type

ts 复制代码
type Person = { 
  name: string;
}
type Student = Person & { grade: number }; // 用交叉类型

interface 继承 type

ts 复制代码
type Person = {
  name: string;
};

interface Student extends Person {
  grade: number;
}

type 继承 interface

ts 复制代码
interface Person {
  name: string;
}

type Student = Person & { grade: number }; // 用交叉类型

interface 使用 extends 实现继承, type 使用交叉类型实现继承。

注意:interface 不能继承一个联合类型

ts 复制代码
type Input = {
  a: string;
};
type Output = {
  b: string;
};

type InputOrOutput = Input | Output;

// 报错:接口只能扩展使用静态已知成员的对象类型或对象类型的交集。
interface C extends InputOrOutput {
  c: string;
}

// 可以用type实现
type C = InputOrOutput & { c: string };

// 使用
const value: C = {
  a: '1',
  b: '2',
  c: '3',
};

4、两者不同点

4.1、interface 可以,type 不行

4.1.1、合并重复声明

ts 复制代码
interface Person {
  name: string;
}

interface Person {
  // 重复声明 interface,就合并了
  age: number;
}

const person: Person = {
  name: 'lin',
  age: 18,
};

重复声明 type ,就报错了

ts 复制代码
type Person = {
  name: string;
};

type Person = {
  // Duplicate identifier 'Person'
  age: number;
};

4.1.2、定义类和抽象类的实现

如果需要定义一个类或抽象类的实现,通常应该使用 interface 而不是 type。interface 可以被类实现,而 type 不能。

ts 复制代码
// 使用 interface 定义抽象类的实现
interface Shape {
  area(): number;
}

abstract class Circle implements Shape {
  abstract radius: number;

  area() {
    return Math.PI * this.radius ** 2;
  }
}

4.2、type 可以,interface 不行

类型别名会给一个类型起个新名字。 类型别名有时和接口很像,但是可以作用于原始值,联合类型,元组以及其它任何你需要手写的类型。

4.2.1、声明基本类型、联合类型、交叉类型、元组

ts 复制代码
// 基本类型
type Name = string; 

type Person = {
  name: Name;
};


// 联合类型
type arrItem = number | string; 

const arr: arrItem[] = [1, '2', 3];


// 交叉类型
type Student = Person & { grade: number }; 

type Teacher = Person & { major: string };


// 元组类型
type StudentAndTeacherList = [Student, Teacher]; 

const list: StudentAndTeacherList = [
  { name: 'lin', grade: 100 },
  { name: 'liu', major: 'Chinese' },
];

4.2.2、定义映射类型

使用 type 可以定义映射类型,根据现有类型创建新类型。

ts 复制代码
type ReadOnly<T> = {
  readonly [K in keyof T]: T[K];
};

type User = {
  name: string;
  age: number;
};

type ReadOnlyUser = ReadOnly<User>;

4.2.3、条件类型

使用 type 可以定义条件类型,根据不同条件返回不同的类型。

ts 复制代码
type NonNullable<T> = T extends null | undefined ? never : T;

type MaybeString = string | null | undefined;
type NonNullMaybeString = NonNullable<MaybeString>;

4.2.4、模板字符串字面量类型

使用 type 可以定义模板字符串字面量类型,用于字符串字面量的静态检查。

ts 复制代码
type Greeting = `Hello, ${string}!`;

// 合法
const greeting: Greeting = "Hello, World!"; 

// 不合法
const invalidGreeting: Greeting = 42; // 报错:不能将类型 42 分配给类型"`Hello, ${string}!`"。

4.2.5、字符串字面量类型和数字字面量类型

使用 type 可以定义字符串字面量类型和数字字面量类型。

ts 复制代码
type Gender = "male" | "female";
type DayOfWeek = 0 | 1 | 2 | 3 | 4 | 5 | 6;

5、总结

interface 和 type 有着相似的功能,但是它们也有各自独有的特点。我们可以把它们区分为以下几点:

5.1、interface适用于

  • 用于声明对象类型的接口
  • 需要继承或声明合并的接口
  • 声明函数类型的接口
  • 需要在类型注释中使用类型的接口

5.2、type适用于

  • 声明原始类型的别名
  • 定义复杂的类型,如交叉类型、联合类型、元组和映射类型
  • 使用泛型的类型别名

通常情况下,当我们主要处理对象时,我们更倾向于使用 interface。而当我们需要更加高级的类型定义时,我们更倾向于使用 type。

如果不清楚什么时候用 interface/type,能用 interface 实现,就用 interface。如果不能就用 type 实现。

相关推荐
拆房老料11 小时前
ONLYOFFICE也能像Microsoft Word和WPS一样分别设置中西文字体
前端·html·word·开源软件·wps
Solis程序员12 小时前
Stripe 幂等表:把「不确定的重试」变成「查表返回」
前端·安全·bootstrap·php·agent
李纲明12 小时前
WordPress 站点变慢:按 TTFB → 缓存 → 查询 → 前端 分层排查(含配置注意)
前端·缓存·性能优化·wordpress·后端开发
程序人生88812 小时前
PDF 转 Word 版式错乱、表格丢失?DocConverter Web 格式互转引擎的保真实践
前端·人工智能·opencv·机器学习·pdf·word
粥里有勺糖13 小时前
安利一下最近用的桌面“Agent” | T3 Code
前端·github·ai编程
xy345313 小时前
Axure 9.0 动态面板基本操作
前端·ui·html·axure·原型·产品设计
不停喝水13 小时前
【前端转全栈java速通课】 项目实战④7-11节 操作数据库-登录-注册-修改密码-注销-mubatis-plus简化crud-
java·前端·数据库
一水鉴天14 小时前
统一对象拓扑(UOT)设计全链定稿:从三件事分离到三继承 之1 20261010(豆包“查看聊天内容”继续)
前端·css
栖凤14 小时前
Java 的 try-catch 在 Agent 里失效了,我用了 5 个模式才兜住
java·前端·python
粥里有勺糖14 小时前
视野修炼第136期 | 前端小恐龙"Deno"被收购
前端·github·ai编程