相同点
都可以声明对象和函数类型
interface Point {x: number;y: number;}interface SetPoint {(x: number, y: number): void;}
type Point = {x: number;y: number;};type SetPoint = (x: number, y: number) => void;
支持扩展
interface Animal {name: string}interface Bear extends Animal {honey: boolean}const bear: Bear = {name: "Winnie",honey: true,}
type Animal = {name: string}type Bear = Animal & {honey: boolean}const bear: Bear = {name: "Winnie",honey: true,}
type Animal = {name: string}interface Bear extends Animal {honey: boolean}
interface Animal {name: string}type Bear = Animal & {honey: boolean}
不同点
type 可以声明基本类型、联合类型或元组类型,而接口不行
type MyNumber = number;type StringOrNumber = string | number;type Point = [number, number];
interface 可以自动合并类型,type 不支持
interface Animal {name: string}interface Animal {tail: boolean}const dog: Animal = {name: "Tom",tail: true,}
type Animal = {name: string}type Animal = {tail: boolean}// ERROR: Duplicate identifier 'Animal'.
利用同名接口自动合并的特性,在开发第三方库的时候,我们就可以为使用者提供更好的安全保障。比如webext-bridge这个库,使用interface定义了ProtocolMap接口,从而让使用者可自由地扩展ProtocolMap接口。
import { ProtocolWithReturn } from 'webext-bridge'declare module 'webext-bridge' {export interface ProtocolMap {foo: { title: string }bar: ProtocolWithReturn<CustomDataType, CustomReturnType>}}
总结
官方推荐用interface,其他无法满足需求的情况下用type。
但其实,因为联合类型和元组类型是很常用的,所以避免不了大量使用type的场景,一些复杂类型也需要通过组装后形成类型别名来使用。
所以,如果想保持代码统一,还是可选择使用type。通过上面的对比,类型别名其实可涵盖interface的大部分场景。
对于React组件中props及state,使用**type**这样能够保证使用组件的地方不能随意在上面添加属性。如果有自定义需求,可通过HOC二次封装。
编写三方库时使用**interface**,其更加灵活自动的类型合并可应对未知的复杂使用场景。
