interface与type算是同一概念的两种句法,类似与函数表达式与函数声明之间的关系,不过两者之间存在一些细微的差别
正常情况
type CarType = {
name: string;
number: number;
sale: boolean;
};
interface CarInterface {
name: string;
number: number;
sale: boolean;
}
这两个声明都定义了一个结构,两者可以相互赋值,在这种情况下实质上两者完全一样
使用类型组合
// 类型组合
type AnimalType = {
dog: string;
cat: string;
};
type HasPig = AnimalType & {
pig: string;
};
interface AnimalInterface {
dog: string;
cat: string;
}
interface HasPigInterface extends AnimalInterface {
pig: string;
}
type 类型别名使用的是 '&'进行扩展, interface 使用的是extends 进行扩展,结果是完全一致的
区别
1、类型别名type更为通用,右边可以是任何类型,包括表达式,而接口声明interface中,右边必须是结构,下面例子类型别名type不能使用接口interface重写
type A = number;
type B = A | string;
这种定义在接口声明中是无法实现的
2、扩展接口时,typescript会检查扩展的接口是否可以赋值,如下:
interface AA {
good(x: number): string;
bad(x: number): string;
}
interface BB extends AA { // 报错: 属性“bad”的类型不兼容
good(x: string | number): string;
bad(x: string): string;
}
而使用type将不会有这种问题,如下:
type AAA = {
good(x: number): string;
bad(x: number): string;
}
type BBB = AAA & {
good(x: string | number): string;
bad(x: string): string;
}
typescript 将会将AAA尽力的拓展,最终结果是重载了bad的签名,而不会抛出错误,得到的结果如下:
type BBB = {
good(x: string | number): string;
bad(x: string | number): string; // typescript重载了bad函数
}
3、同一作用域中的多个同名接口将自动合并,而类型别名将会导致编译报错
interface CCC {
a: string
}
interface CCC {
b: string
}
// CCC => { a: string; b: string }
但这里要注意的是,两个接口声明不能有冲突,否则将会报错,如下a冲突了:
interface DDD {
a: string
}
interface DDD {
a: number // Error: 后续属性声明必须属于同一类型。属性“a”的类型必须为“string”,但此处却为类型“number”。ts(2717)
}
而 type 将直接报错,如下:
type EEE = {}
type EEE = {} // 报错: 标识符“EEE”重复。ts(2300)
总结
建议日常通常采用type,这样可以达到拓展性,无法实现需求再改用interface