事实上这两者非常的像,interface 能做的,type 基本都能做。但是两者还是有一些差别,这也就是本文想描述的事情。
1. interface 只能表示像对象那种结构的类型
interface 只能表示像对象那种结构的类型,如果想表示 JS 中的原始类型(undefined
, null
, boolean
, string
,number
)只能交给 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,会报下面的错误:
下面是报错信息:
当然了,你可能会有疑问,interface 中使用 : 而不是 in 操作符呢?也不行。比如下面这个示例,也不支持下面这种组合 type 的写法:
type Keys = "小王" | "小文"
type X = {
[key in Keys]: string
}
type XX = keyof Keys;
interface Y {
[k: XX]: number
}
总之 interface 中,表示对象的类型方面没 type 灵活。
3. type 声明的类型不能重名,interface 声明的重命名会合并在一块
比如下面这样,就报错了:
大家可以看这个线上例子
借助这个特性,我们想往全局的 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
}
这个也得用 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。