CodeSky 代码之空

随手记录自己的学习过程

TypeScript type 和 interface 的区别

2022-05-03 22:59分类: JavaScript评论: 1

从使用的角度去看,这可能是个老生常谈的问题,就连 TypeScript 官方文档都会给你一个个介绍:

Interfaces vs Types in TypeScript

Documentation - Everyday Types

Learn about difference between Type & Interface in Typescript

具体来说(翻译成中文来说):

  1. 基本类型:用 type ,因为 interface 做不到

    1type Nullish = null | undefined;
    2type Fruit = 'apple' | 'pear' | 'orange';
    3type Num = number | bigint;
    4
  2. 元组:用 type,因为 interface 也做不到

    1type row = [colOne: number, colTwo: string];
    2
  3. 函数:用 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
  4. UnionType:用 type ,因为 interface 没法 union

    1type Fruit = 'apple' | 'pear' | 'orange';
    2type Vegetable = 'broccoli' | 'carrot' | 'lettuce';
    3
    4// 'apple' | 'pear' | 'orange' | 'broccoli' | 'carrot' | 'lettuce';
    5type HealthyFoods = Fruit | Vegetable;
    6
  5. 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
  6. 除此以外,通常都用 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

至此,所有 typeinterface 的场景看上去理得泾渭分明,那为什么还会有这篇文章呢,因为今天遇到了一个 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 却不能。导致了这一差异性:

Index signature is missing in type (only on interfaces, not on type alias) · Issue #15300 · microsoft/TypeScript

(简单的来说还是实现成本略高。

评论 (1)

pan2023年8月27日 11:07

干货满满