TypeScript协变、逆变、双向协变、不可变剖析,解密联合类型转交叉类型
2023-01-30 11:54:30
TypeScript 的类型协变、逆变和双向协变
在 TypeScript 的类型系统中,协变 、逆变 和双向协变 是三个至关重要的概念,它们了类型在不同场景下的行为,对 TypeScript 的类型推断和类型检查产生重大影响。了解这些概念将让你深入理解 TypeScript 的类型系统,并编写出更健壮和可维护的代码。
协变
协变 是指子类型可以赋值给父类型。这在 TypeScript 中非常常见。例如,如果 Animal
是一个父类,而 Dog
和 Cat
是它的子类,那么我们可以将 Dog
或 Cat
赋值给 Animal
类型变量。
interface Animal {
name: string;
}
class Dog implements Animal {
name: string;
bark() {}
}
class Cat implements Animal {
name: string;
meow() {}
}
function printAnimalName(animal: Animal) {
console.log(animal.name);
}
const dog = new Dog();
const cat = new Cat();
printAnimalName(dog); // "Dog"
printAnimalName(cat); // "Cat"
在这个例子中,Dog
和 Cat
都派生自 Animal
,所以我们可以将它们赋值给 Animal
类型变量。当我们调用 printAnimalName
函数时,TypeScript 会自动将 Dog
和 Cat
对象转换为 Animal
类型,以便与函数参数匹配。
逆变
逆变 是指父类型可以赋值给子类型。这在 TypeScript 中不太常见,但也有其用途。例如,如果我们有一个比较器函数可以比较两个 Animal
对象的大小,那么我们可以使用 Animal
类型作为比较器函数的参数类型。
interface Animal {
name: string;
}
class Dog implements Animal {
name: string;
bark() {}
}
class Cat implements Animal {
name: string;
meow() {}
}
function compareAnimals(a: Animal, b: Animal): number {
if (a.name < b.name) {
return -1;
} else if (a.name > b.name) {
return 1;
} else {
return 0;
}
}
const dog = new Dog();
const cat = new Cat();
console.log(compareAnimals(dog, cat)); // -1
console.log(compareAnimals(cat, dog)); // 1
在这个例子中,Animal
类型用作比较器函数的参数类型。当我们调用 compareAnimals
函数时,TypeScript 会自动将 Dog
和 Cat
对象转换为 Animal
类型,以便与函数参数匹配。
双向协变
双向协变 是指子类型和父类型可以相互赋值。这在 TypeScript 中很少见,只有少数类型具有这种特性。例如,Array
类型就是双向协变的。
const numbers: number[] = [1, 2, 3];
const strings: string[] = ["a", "b", "c"];
const mixedArray: (number | string)[] = numbers; // OK
在这个例子中,numbers
是一个 number[]
类型的数组,而 strings
是一个 string[]
类型的数组。我们可以将 numbers
赋值给 (number | string)[]
类型的变量 mixedArray
,这是因为 number[]
和 string[]
都是 (number | string)[]
类型的子类型。
不可变
除了协变、逆变和双向协变之外,TypeScript 中还有一个重要的概念叫不可变 。不可变 是指一个类型不能赋值给任何其他类型。这通常用于 primitive 类型,如 number
、string
和 boolean
。
const numberValue: number = 123;
numberValue = "abc"; // 错误:不能将字符串分配给数字
在这个例子中,numberValue
被声明为 number
类型,所以我们不能将字符串 "abc" 赋值给它。
结论
协变、逆变、双向协变和不可变是 TypeScript 类型系统中的关键概念。理解这些概念可以让你更深入地理解 TypeScript 的类型推断和类型检查,编写出更健壮和可维护的代码。
常见问题解答
-
什么是协变?
协变是指子类型可以赋值给父类型。 -
什么是逆变?
逆变是指父类型可以赋值给子类型。 -
什么是双向协变?
双向协变是指子类型和父类型可以相互赋值。 -
什么是不可变?
不可变是指一个类型不能赋值给任何其他类型。 -
协变、逆变和双向协变有什么实际应用?
协变和逆变用于实现多态性,双向协变用于实现泛型容器。