TS 中 type 和 interface 的区别

3,971 阅读3分钟

事实上这两者非常的像,interface 能做的,type 基本都能做。但是两者还是有一些差别,这也就是本文想描述的事情。

1. interface 只能表示像对象那种结构的类型

interface 只能表示像对象那种结构的类型,如果想表示 JS 中的原始类型(undefined, null, boolean, stringnumber)只能交给 type 老大哥:

type A = string

同时,type 也可以像 interface 一样表示对象类型,只不过语法有一点点不一样:

type Reptile = {
    genus: string
}

另外,说一点,使用 interface 表示函数类型语法有点特殊:

interface SearchFunc {
    (source: string, subString: string): boolean;
}

对比起来还是 type 表示函数更直观:

type SearchFunc = (source: string, subString: string) => boolean;

但是如果描绘的都是一个函数,且函数这个对象上有属性,那二者也还是很相像:

type TFnWithProperties = { 
    (x: number): number; 
    prop: string;
}

interface IFnWithProperties {
    (x: number): number;
    prop: string; 
}

2. type 可以动态计算属性,interface 没那么强大。

在 interface 中,我们可以这么来表示一个对象:

interface Y {
    [k: string]: number
}

这里 k 的类型可以是 string 或者 number,但是只能这两个中的一个。上面代码中,我们指定 k 的类型是 string

type 在这方面就表现得更强大,它可以使用计算属性,可以限制属性包含某几个。

下面这个例子中, X 就只包含 小王小文 两个属性。

type Keys = "小王" | "小文"

type X = {
  [key in Keys]: string
}

const test: X = {
    '小王': '肌肉男',
    '小文': '也是肌肉男'
}

interface 就不支持上面这种写法的,如果我们把上面的语法用在 interface,会报下面的错误:

image.png

下面是报错信息:

image.png

当然了,你可能会有疑问,interface 中使用 : 而不是 in 操作符呢?也不行。比如下面这个示例,也不支持下面这种组合 type 的写法:

type Keys = "小王" | "小文"

type X = {
  [key in Keys]: string
}

type XX = keyof Keys;

interface Y {
    [k: XX]: number
}

image.png

总之 interface 中,表示对象的类型方面没 type 灵活。

3. type 声明的类型不能重名,interface 声明的重命名会合并在一块

比如下面这样,就报错了:

image.png

大家可以看这个线上例子

借助这个特性,我们想往全局的 window 属性上挂载一些自定义属性时,可以使用 interface:

interface Window {
    xxx: string;
}

同时,像 JS 内置库里面的方法也很适合用 interface 定义,比如 Array 用 interface 定义,后续再增加了新的语法,如 ES2022,只要再新的文件新加就好了。

4. 两者继承的方法不同

interface 使用 extends 继承

interface IStateWithPop extends TState { 
    population: number;
}

type 可以使用 & 关键字

type TStateWithPop = IState & { population: number; };

但是 interface 不能继承一个联合类型,比如:

type Input = { 
    a: string
}; 
type Output = { 
    b: string
};

type InputOrOutput = Input | Output

interface C extends InputOrOutput {
    c: string
}

CleanShot 2022-09-30 at 13.53.12@2x.png

这个也得用 type 写:

type Input = { 
    a: string
}; 
type Output = { 
    b: string
};

type InputOrOutput = Input | Output
type C = InputOrOutput & {c: string}

const c:C = {
    a: '1',
    b: '2',
    c: '3'
}

总结

其实二者还是非常非常像的,一般在工作中可能没必要特别纠结,符合大家使用规范即可。如果写库的时候,考虑到后续兼容性,可以优先使用一下 interface;在工作中,由于 interface 有默认合并,如果顾忌这方面,可以使用 type。