TypeScript type 和 interface 的区别
从使用的角度去看,这可能是个老生常谈的问题,就连 TypeScript 官方文档都会给你一个个介绍:
Interfaces vs Types in TypeScript
Documentation - Everyday Types
Learn about difference between Type & Interface in Typescript
具体来说(翻译成中文来说):
-
基本类型:用
type
,因为interface
做不到1type Nullish = null | undefined; 2type Fruit = 'apple' | 'pear' | 'orange'; 3type Num = number | bigint; 4
-
元组:用
type
,因为interface
也做不到1type row = [colOne: number, colTwo: string]; 2
-
函数:用
type
,因为可读性1// via type 2type Sum = (x: number, y: number) => number; 3 4// via interface 5interface Sum { 6 (x: number, y: number): number; 7} 8
-
UnionType:用
type
,因为interface
没法 union1type Fruit = 'apple' | 'pear' | 'orange'; 2type Vegetable = 'broccoli' | 'carrot' | 'lettuce'; 3 4// 'apple' | 'pear' | 'orange' | 'broccoli' | 'carrot' | 'lettuce'; 5type HealthyFoods = Fruit | Vegetable; 6
-
MappedType:用
type
,因为interface
做不到:1type Fruit = 'apple' | 'orange' | 'banana'; 2 3type FruitCount = { 4 [key in Fruit]: number; 5} 6 7const fruits: FruitCount = { 8 apple: 2, 9 orange: 3, 10 banana: 4 11}; 12
-
除此以外,通常都用 interface,interface 有一个特殊性需要注意:
1interface Window { 2 title: string 3} 4 5interface Window { 6 ts: TypeScriptAPI 7} 8 9const src = 'const a = "Hello World"'; 10window.ts.transpileModule(src, {}); 11
那么,为什么我们说除此以外都用 interface
呢,因为官方是这么说的:
Performance · microsoft/TypeScript Wiki
Interfaces create a single flat object type that detects property conflicts, which are usually important to resolve! Intersections on the other hand just recursively merge properties, and in some cases produce
never
. Interfaces also display consistently better, whereas type aliases to intersections can't be displayed in part of other intersections. Type relationships between interfaces are also cached, as opposed to intersection types as a whole. A final noteworthy difference is that when checking against a target intersection type, every constituent is checked before checking against the "effective"/"flattened" type.
出于对检查性能的考虑,也建议你使用 interface
。
当然,如果要跳类型体操,那毫无疑问用的也是 type
。
至此,所有 type
和 interface
的场景看上去理得泾渭分明,那为什么还会有这篇文章呢,因为今天遇到了一个 case:
1// it works!
2enum A {
3 a,
4 b
5}
6
7type V = {
8 a: A
9}
10
11type CustomData<T> = T extends {
12 [key: string]: string | number
13} ? T : never
14
15const a: CustomData<V> = {
16 a: A.a
17}
18
1const enum A {
2 a,
3 b
4}
5
6interface K {
7 a: A
8}
9
10type V = {
11 a: A
12}
13
14type CustomData<T> = T extends {
15 [key: string]: string | number
16} ? T : never
17
18const a: CustomData<K> = {
19 // Type 'A' is not assignable to type 'never'.(2322)
20 a: A.a
21}
22
主要原因也是出于「性能」和「静态分析」时的考虑,上文中我们讲到了 interface
可以多次定义、扩充和覆盖;而 type
是一锤定音的,那么对于 type
来说,我们可以直接一口气推导到最终结果,而 interface
却不能。导致了这一差异性:
(简单的来说还是实现成本略高。
评论 (1)
干货满满