跳到主要内容

type和interface的区别

TypeScript中的type和interface既有相似之处又有不同之处。以下是它们之间的主要区别:

语法

  • type语法:使用关键字"type";
  • interface语法:使用关键字"interface"。

定义对象

  • type可以表示不仅仅是对象、还包括可以代表基本类型、联合类型、元组、函数类型等;
  • interface只能表示对象(或者说class)类型,对于其他类型需要使用type。

同名合并

  • type不支持同名合并;
  • interface支持同名合并。

同名合并是指在多个interface中定义了同名属性或方法,TypeScript会将它们合并成一个。举个例子:

interface User {
name: string;
}

interface User {
age: number;
}

const user: User = {
name: ‘John’,
age: 25
};

在这个例子中,两个User接口都定义了不同的属性。最终的User接口会包含两个属性,name和age。

继承和实现

  • type不支持继承和实现;
  • interface可以通过extends实现继承,通过implements实现接口。

类型别名和接口的不同使用方式

  • 可以使用type来定义类型别名,这样可以使代码更简洁、可读性更好;
  • 接口可以帮助以一种结构化的方式描述对象的形状,而且可以使用interface来定义类的形状。

交叉类型

  • type支持交叉类型操作符"&";
  • interface不支持交叉类型操作符"&"。

交叉类型可以将多个接口或类型合并为一个。例如:

type a = {
id: number;
}

type b = {
name: string;
}

type c = a & b; // c的类型为{id: number, name: string}

可索引类型

  • type支持数字和字符串索引的混合;
  • interface只支持字符串索引。

可索引类型传递的是索引到的属性类型,索引的类型也称为索引签名。在type中,索引签名可以是数字索引类型、字符串索引类型、混合索引类型。在interface中,索引签名只支持字符串索引类型,即用字符串作为key来查找属性值。

类型推断

  • type无法确保属性值的类型,它给出的是类型之间的相互关系;
  • interface可以确保属性值的类型,给出的是具体的属性值类型。此外,interface可以更好地推断类型。

使用场景

  • Type适合描述数据类型,支持联合类型联合、交叉类型合并等操作,在实际开发中一般用于描述组件props或者Redux的store类型等;
  • Interface适合描述对象

可读性和可维护性

  • Interface相比type拥有更好的可读性和可维护性。

在声明对象或类的类型时,Interface可以为每一个属性或方法添加注释、说明其用处,将逻辑与数据结合。这比使用type来声明可读性更高并且更有条理性,因为对于type,每个属性的意义只能通过变量名来推测,这可以使维护和更新某些代码更加困难。

交互式开发

  • Interface可以在交互式开发工具中使用,提高了开发效率;
  • Type不适合在交互式开发工具中使用。

交互式工具有能力从interface的描述中提取包含的属性和方法列表以及类型信息,这使得IDE和编辑器可以在编码时提供更准确和全面的信息。

Type Aliasing

Type Aliasing是一种创建type的方式,允许给一个类型或联合类型取一个新的名字。其实它是类似于type声明的一个类型别名机制,不过更加简单,使得代码更易读。

重载

Interface只能申明一次,不能重复。Type可以通过联合类型来实现重载,最终调用是不同的。

类型提取

Type构造器存在于umion、intersection、utility 和 other advanced patterns 中的类型推断中。 而Interface更适合于描述具体特性的结构,尤其是使用反射时,可以更加准确、清晰地描述类型信息。

属性的可选性

  • Type可以将所有属性都定义为可选的,通过"?"操作符;
  • Interface可以将属性定义为可选的,通过在属性名后面添加"?"操作符;

对于Type来说,例如:

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

这将会定义一个User类型的对象,它具有可选的name、age和address属性。

而在Interface中,可以通过如下方式来定义:

interface User {
name?: string;
age?: number;
address?: string;
}

映射类型

Type具有映射类型,可以将现有类型中的所有属性都映射到新的类型中。例如:

type Partial<T> = {
[P in keyof T]?: T[P];
};

这将为任何类型T定义一个Partial类型,它将接受T的所有属性,并使它们变成可选的。如果T具有required、readonly、或可选属性,则Partial将映射这些属性。相比之下,Interface不支持映射类型。

类型的扩展

  • Type可以扩展Type;
  • Interface可以扩展Interface和Class。

例如,在Type中,可以使用"&"运算符将多个Type组合在一起:

type User = {
name: string;
}

type Employee = {
id: number;
}

type Worker = User & Employee;

而在Interface中,可以使用extends关键字来扩展其他Interface或Class:

interface User {
name: string;
}

interface Employee extends User {
id: number;
}

class Person {
age: number;
}

interface Worker extends Person {
salary: number;
}

Worker既扩展了Person,又扩展了User。

总结1:Type本身更强大,但它在代码的可读性、扩展性和可维护性中弱于Interface。如果要定义一个简单对象类型或做类型别名,Type更好用。如果需要定义对象、类、实现和扩展等,则Interface往往更直接和冗长,但更易于阅读和理解。

总结2:虽然Type和Interface的语义和功能有所重叠,但它们的设计哲学不同。Type的设计思想更偏向于逻辑和计算类型,适用于编写高度抽象的代码。而Interface则更加注重实体和概念,适用于对于复杂、结构化的类和对象类型建模。在使用时,我们应该根据需求来选择使用哪种语法。