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则更加注重实体和概念,适用于对于复杂、结构化的类和对象类型建模。在使用时,我们应该根据需求来选择使用哪种语法。