feng xiaohan

TS高级-类型兼容(协变、逆变、双向协变)

类型兼容

所谓的类型兼容性,就是用于确定一个类型是否能赋值给其他的类型。typeScript 中的类型兼容性是基于结构类型的(也就是形状),如果 A 要兼容 B 那么 A 至少具有 B 相同的属性。

协变

如果类型 S 可以赋值给类型 T,那么我们就说类型 T 是类型 S 的协变类型。简单来说,就是子类型可以赋值给父类型,子类型中的属性必须完全覆盖父类型中的属性

而这类型也被称为鸭子类型(一只鸟走路像鸭子,游泳也像,做什么都像鸭子,那么这只鸟就可以成为鸭子类型)。

// 父类型
interface A {
  name: string;
  age: number;
}
// 子类型
interface B {
  name: string;
  age: number;
  sex: string;
}
let a: A = {
  name: "张三",
  age: 18,
};
let b: B = {
  name: "李四",
  age: 19,
  sex: "女",
};
// 父 = 子
a = b; // 协变

协变是针对值的。

逆变

协变赋值的相反操作,对于函数来说,拥有父类型的函数赋值给子类型的函数:

let fnA = (params: A) => {};
let fnB = (params: B) => {};
// 子 = 父
fnB = fnA; // 逆变

逆变是针对函数(函数参数)的。

双向协变

是子类型和父类型可以互相赋值。

注意:这在 TypeScript2.0 之前允许这么操作,TypeScript2.0 之后发现这样是不安全的,如果你需要支持双向协变的话需要自己去开启这个属性:

// tsconfig.json
"compilerOptions": {
    "strictFunctionTypes": false,
}