协变与逆变
TypeScript中的型变关系
1. 型变概述
| 型变 | 说明 | 示例 |
|---|---|---|
| 协变 | 子类型关系保持方向 | Dog[] 是 Animal[] 的子类型 |
| 逆变 | 子类型关系反转 | (x: Animal) => void 是 (x: Dog) => void 的子类型 |
| 不变 | 无子类型关系 | 既是协变也是逆变 |
| 双变 | 同时允许协变和逆变 | TS 函数参数的默认行为 |
2. 协变
interface Animal {
name: string;
}
interface Dog extends Animal {
breed: string;
}
// Dog 是 Animal 的子类型 → Dog[] 是 Animal[] 的子类型(协变)
const dogs: Dog[] = [{ name: 'Rex', breed: 'Husky' }];
const animals: Animal[] = dogs; // 协变
// Promise 也是协变的
type AsyncDog = Promise<Dog>;
type AsyncAnimal = Promise<Animal>;
const ap: AsyncAnimal = (async () => ({ name: 'Rex', breed: 'Husky' }))() as AsyncDog;
3. 逆变
// 函数参数是逆变的
type AnimalHandler = (animal: Animal) => void;
type DogHandler = (dog: Dog) => void;
// DogHandler 是 AnimalHandler 的子类型
const dogHandler: DogHandler = (dog) => console.log(dog.breed);
const animalHandler: AnimalHandler = dogHandler; // 逆变
4. strictFunctionTypes
{ "compilerOptions": { "strictFunctionTypes": true } }
启用后函数参数严格逆变,禁用则双变。
5. 型变与泛型
// 协变位置
interface Box<out T> {
// TS 5.0+ 使用 out 修饰符
get(): T;
}
// 逆变位置
interface Sink<in T> {
// TS 5.0+ 使用 in 修饰符
consume(value: T): void;
}
// 不变
interface Storage<in out T> {
// 同时 in out
get(): T;
set(value: T): void;
}