摘要
Typescript 的核心原则之一是对值所具有的结构进行类型检查,接口(interface) 和类型别名(type)的作用就是为代码定义契约。然而 interface 和 type 的区别是什么,在开发中使用哪个,这些问题困扰着开发者。本文通过代码示例,首先对网上常见的 3 个错误观点进行纠正,然后总结了两者的 4 个不同之处。最后给出了使用 interface 和 type的建议。为不是使用 TypeScript 编写的库编写第 3 方环境类型定义时 或 我们的库是用 TypeScript 编写的并且环境类型定义是自动生成的使用 interface,在 React Props 和 State 建议使用 type
在线运行代码:codesandbox.io/s/suspiciou…
Introduce
TypeScript 允许类型与使用它们的变量分开定义,Interface 和 Type 允许不同的变量 / 对象之前公用。TypeScript 官网指出,“类型别名可以有点像接口,但是有一些细微的差别”。
错误观点
1. interface 创建新名称,type 不会创建新的名称——不会抛出错误
创建一个接口 pointInterface 和 一个 类型 pointType,声明 point_interface 和 point_type。未声明对象中 y 属性。 TypeScript 基础使用链接。
interface PointInterface {
x: number;
y: number;
}
type PointType = {
x: number;
y: number;
};
const point_interface: PointInterface = { x: 1 };
const point_type: PointType = { x: 1 };
ts 给出了相同的报错
// TS Error:
Property 'y' is missing in type '{ x: number; }' but required in type 'pointInterface'.ts(2741)
errorPoints.ts(3, 3): 'y' is declared here.
Property 'y' is missing in type '{ x: number; }' but required in type 'pointType'.ts(2741)
errorPoints.ts(8, 3): 'y' is declared here.
2. type 不支持扩展(extends) 或 实现(implemented)
// case2: type supports extends
interface ThreeDimensions extends PointType {
z: number;
}
// case2: type can be used by implements
class Rectangle implements PointType {
x = 2;
y = 3;
}
由 type 扩展来的接口也可以作为类的约束:
// case2: interface extends from type
class RectanglePrism implements ThreeDimensions {
x = 2;
y = 3;
z = 4;
}
type 和 interface 支持混合使用作为类的约束:
interface Shape {
area(): number;
}
interface Perimeter {
perimiter(): number;
}
class RectangleDeep implements PointType, Shape, Perimeter {
x = 2;
y = 3;
area() {
return this.x * this.y;
}
perimiter() {
return 2 * (this.x + this.y);
}
}
3. type 不支持从其他 type 中扩展
type 支持通过交集运算符 & 进行类型别名扩展
type RectangleDeepType = PointType & Shape & Perimeter
class RectangleDeep implements RectangleDeepType {
x = 2;
y = 3;
area() {
return this.x * this.y;
}
perimiter() {
return 2 * (this.x + this.y);
}
}
Interface & type 区别
1. type 适用于所有类型,interface 仅适用于对象
interface 受限于声明方式,仅适用于对象类型。
// case1: type use basic type
type FirstName = string;
const firstName: FirstName = "firstName";
2. 如果在 type 定义中使用联合运算符(|),则不能在具有类型别名的类上使用 implements
type PointType = {
x: number;
y: number;
};
interface Shape {
area(): number;
}
interface Perimeter {
perimiter(): number;
}
type RectangleDeepType = (PointType | Shape) & Perimeter;
class RectangleDeep implements RectangleDeepType {
x = 2;
y = 3;
area() {
return this.x * this.y;
}
perimiter() {
return 2 * (this.x + this.y);
}
}
这是完全符合逻辑的。 类可以视为蓝图,不能实现一个或另一个形状结构。
3. 如果在 extends 定义中使用联合运算符,则不能在具有 type 的接口上使用扩展
// case 3: interface extends cannot support type |
type ShapeOrPermiter = Shape | Perimeter;
interface RectangleShape extends ShapeOrPermiter {}
同样,与 2 类似,interface 是一个静态蓝图——它不能以一种或另一种形式存在,因此不能通过 union 类型合并来扩展。
4. 声明合并不适用于 type
多次定义同一个接口,它的定义将合并为一个:
// case 4: merge
interface Table {
price: number;
}
interface Table {
size: number;
}
const table: Table = {
size: 100,
price: 200
};
type Pen = {
price: number;
};
type Pen = {
size: number;
};
这不适用于类型别名,因为类型是一个唯一的类型实体(对于全局或模块范围):
何时使用 interface
通过 interface 合并声明非常重要,当我们为不是使用 TypeScript 编写的库编写第 3 方环境类型定义时,如果缺少某些定义,使用方可以选择扩展它们。
如果我们的库是用 TypeScript 编写的并且环境类型定义是自动生成的,则同样适用。
这是唯一的用例,应该始终使用 interface 而不是 type!
何时使用 type
在React Props 和 State 定义中,建议使用类型别名:
- 写成 type Props = {} 更短
- 使用语法是一致的(通常没有 interface 和 type 混用的必要)
- 你的公共组件 Props/State 实现不能被修改,因此,组件的消费者永远不需要利用接口声明合并。
// BAD
interface Props extends OwnProps, InjectedProps, StoreProps {}
type OwnProps = {...}
type StoreProps = {...}
// GOOD
type Props = OwnProps & InjectedProps & StoreProps
type OwnProps = {...}
type StoreProps = {...}
总结
本文总结了 TypeScript 中接口(interface) 和类型别名(type)的作用和不同之处。两者的作用都是进行类型检查。首先对常见的错误观点进行纠正,interface 和 type 都会创建一个新的名称;type 支持扩展和实现;type 支持从其他 type 中扩展。其次梳理了两者的区别:type可以作用于基本数据类型,interface 只能作用于对象;使用了联合运算符(|) 的 type 不能被 class 实现;使用了联合运算符(|) 的 type 不能被 interface extends;声明合并不适用于 type。最后我们总结了,为不是使用 TypeScript 编写的库编写第 3 方环境类型定义时 或 我们的库是用 TypeScript 编写的并且环境类型定义是自动生成的使用 interface,在 React Props 和 State 建议使用 type。
在线运行代码:codesandbox.io/s/suspiciou…
引用
[1] typescript.bootcss.com/interfaces.…
[4] www.geeksforgeeks.org/what-are-ty…
[5] www.typescriptlang.org/docs/handbo…
[6] www.w3schools.com/typescript/…
开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 1 天,点击查看活动详情