赋值兼容性
TypeScript 中存在两种兼容性,即子类型兼容性和赋值兼容性。子类型兼容性与赋值兼容性有着密切的联系,若类型 S 是类型 T 的子类型,那么类型 S 能够赋值给类型 T。在赋值语句中,变量和表达式之间需要满足赋值兼容性;在函数调用语句中,函数形式参数与实际参数之间也要满足赋值兼容性。示例如下:
type T = { x: number };
type S = { x: number; y: number };
let t: T = { x: 0 };
let s: S = { x: 0, y: 0 };
t = s;
function f(t: T) {}
f(t);
f(s);
此例中,S 是 T 的子类型,那么 S 可以赋值给 T,同时可以使用 S 来调用接收 T 类型参数的函数。
子类型兼容性
在绝大多数情况下,如果类型 S 能够赋值给类型 T,那么也意味着类型 S 是类型 T 的子类型。针对这个规律只有以下几种例外情况。
-
any类型。在赋值兼容性中,any类型能够赋值给任何其他类型,但any类型不是其他类型的子类型,因为any类型是顶端类型。 -
数值型枚举与
number类型。number类型可以赋值给数值型枚举类型,但number类型不是数值型枚举的子类型,反而数值型枚举是number类型的子类型。示例如下:enum E { A, B, } const s: number = 0; const t: E = s; -
带有可选属性的对象类型。如果对象类型
T中有可选属性M,那么对象类型S也可以赋值给对象类型T,即使S中没有属性M。示例如下:
type T = { x: number; y?: number };
type S = { x: number };
const s: S = { x: 0 };
const t: T = s;
此例中,类型 S 能够赋值给类型 T,但是类型 S 不是类型 T 的子类型,因为类型 T 中的属性 y 不能够在类型 S 中找到对应的属性定义。