探索 TypeScript 类型系统中的协变和逆变
2023-12-02 23:36:31
TypeScript 类型中的逆变协变
类型推导是TypeScript中最强大的特性之一,它允许编译器自动推断变量和表达式的类型。在类型推断过程中,TypeScript 会使用协变和逆变规则来确定类型的兼容性。
协变
协变是指当子类型的值可以安全地赋值给父类型时,子类型和父类型是兼容的。例如,string
是 any
的子类型,因为任何字符串值都可以安全地赋值给 any
变量。
逆变
逆变是指当父类型的值可以安全地赋值给子类型时,父类型和子类型是兼容的。例如,any
是 string
的父类型,因为任何值都可以安全地赋值给 string
变量。
双向协变
双向协变是指子类型和父类型都可以安全地相互赋值。例如,number
和 string
是双向协变的,因为数字值可以安全地赋值给字符串变量,反之亦然。
不变
不变是指子类型和父类型都不能安全地相互赋值。例如,boolean
和 number
是不变的,因为布尔值不能安全地赋值给数字变量,反之亦然。
类型推断中的协变和逆变
TypeScript 在类型推断过程中会使用协变和逆变规则来确定类型的兼容性。例如,在下面的代码中:
function foo(x: string) {
return x.toUpperCase();
}
let y: any = "hello";
foo(y);
TypeScript 会使用协变规则来确定 string
和 any
是兼容的,因此 foo()
函数可以被调用。
在下面的代码中:
function bar(x: any) {
x.toUpperCase();
}
let z: string = "hello";
bar(z);
TypeScript 会使用逆变规则来确定 any
和 string
是兼容的,因此 bar()
函数可以被调用。
协变和逆变的应用
协变和逆变在TypeScript中有很多应用,其中一些最常见的应用包括:
- 泛型编程:协变和逆变允许泛型类型在不同的类型上工作,而无需重新编写代码。
- 函数重载:协变和逆变允许函数重载,其中函数的参数或返回值的类型可以根据调用函数的类型而改变。
- 类型转换:协变和逆变允许在类型之间进行转换,而不会丢失任何信息。
总结
协变和逆变是TypeScript中非常重要的概念,它们允许编译器自动推断变量和表达式的类型。协变和逆变在TypeScript中有很多应用,其中一些最常见的应用包括泛型编程、函数重载和类型转换。
练习题
- 以下代码中的
foo()
函数可以被调用吗?为什么?
function foo(x: string) {
return x.toUpperCase();
}
let y: number = 123;
foo(y);
- 以下代码中的
bar()
函数可以被调用吗?为什么?
function bar(x: any) {
x.toUpperCase();
}
let z: boolean = true;
bar(z);
- 以下代码中的
baz()
函数可以被调用吗?为什么?
function baz(x: string | number) {
return x.toUpperCase();
}
let w: string = "hello";
let v: number = 123;
baz(w);
baz(v);
答案
- 不可以。
number
不是string
的子类型,因此 TypeScript 无法使用协变规则来确定它们是兼容的。 - 可以。
boolean
是any
的子类型,因此 TypeScript 可以使用逆变规则来确定它们是兼容的。 - 可以。
string
和number
都是string | number
的子类型,因此 TypeScript 可以使用协变规则来确定它们是兼容的。