小册
这是我整理的学习资料,非常系统和完善,欢迎一起学习
类型系统层级
TypeScript 的类型系统是强类型和静态类型的,这为开发者提供了强大的类型检查和类型安全保障,同时也增加了一定的学习复杂性。为了更好地理解 TypeScript 的类型系统,本文将全面介绍其类型系统层级,包括顶层类型(Top Type)和底层类型(Bottom Type),以及在这个层次结构中如何处理和操作各种类型。理解 TypeScript 的类型系统层级有助于我们更好地使用和掌握 TypeScript,写出更健壮、可维护的代码。
1. 顶层类型(Top Type)
顶层类型是所有其他类型的父类型,这意味着在 TypeScript 中的任何类型都可以看作是顶层类型的子类型。TypeScript 中有两个特殊的顶层类型:any
和unknown
。
1.1 any 类型
any
类型是 TypeScript 的一个逃生窗口,它可以接受任意类型的值,并且对 any
类型的值进行的任何操作都是允许的。使用 any
类型,可以使我们绕过 TypeScript 的类型检查。下面的例子展示了 any
类型的灵活性:
let a: any = 123; // OK
a = 'hello'; // OK
a = true; // OK
a = { id: 1, name: 'Tom' }; // OK
a.foo(); // OK
我们可以看到,我们可以将任何类型的值赋给 any
类型的变量,甚至可以对 any
类型的值进行我们想要的任何操作,而 TypeScript 编译器并不会对此做出任何投诉。然而,正是由于其超高的灵活性,使得 any
类型在一定程度上削弱了 TypeScript 的类型安全性,因此在我们编写 TypeScript 代码时,应尽量避免使用 any
类型。
1.2 unknown 类型
unknown
类型与 any
类型在接受任何类型的值这一点上是一样的,但 unknown
类型却不能像 any
类型那样对其进行任何操作。我们在对 unknown
类型的值进行操作之前,必须进行类型检查或类型断言,确保操作的安全性。
let u: unknown = 123; // OK
u = 'hello'; // OK
u = true; // OK
u = { id: 1, name: 'Tom' }; // OK
// Error: Object is of type 'unknown'.
// u.foo();
if (typeof u === 'object' && u !== null) {
// OK after type check
console.log((u as { id: number,
name: string }).name);
}
在这个例子中,我们对 unknown
类型的值 u
进行了类型检查,然后通过类型断言安全地访问了其 name
属性。
2. 底层类型(Bottom Type)
与顶层类型相对,底层类型是所有类型的子类型。这意味着,在类型系统的层次结构中,任何类型都可以被看作是底层类型的超类型。在 TypeScript 中,never
类型是唯一的底层类型。
never
类型用来表示永远不可能存在的值的类型。比如,一个永远抛出错误或者永远处于死循环的函数的返回类型就是 never
。
function error(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {}
}
在上面的代码中,函数 error
和 infiniteLoop
的返回类型都是 never
,这是因为这两个函数都永远不会有返回值。
3. 对比:顶层类型 vs 底层类型
顶层类型和底层类型是 TypeScript 类型系统的两个重要组成部分,它们各自扮演着不同的角色。
顶层类型 any
和 unknown
能够接受任何类型的值,这使得我们可以灵活地处理不确定类型的数据。然而,any
类型和 unknown
类型在使用上有着重要的区别:any
类型允许我们对其进行任何操作,而 unknown
类型则要求我们在操作之前进行类型检查或类型断言,以确保类型的安全性。
底层类型 never
有点特殊,它表示一个永远不会有值的类型。在实际开发中,我们可能很少直接使用 never
类型,但是它在 TypeScript 的类型推断和控制流分析中起着非常重要的作用。
- 理解 TypeScript 的类型系统层级有助于我们编写更健壮、可维护的 TypeScript 代码。尽管
any
类型提供了很大的灵活性,但是它的滥用可能会削弱 TypeScript 的类型安全性。因此,我们应尽量避免使用any
类型,而优先使用unknown
类型和类型断言、类型保护等方式来处理不确定类型的数据。 - 同时,虽然我们可能很少直接使用
never
类型,但是理解它的含义和用法,对于我们理解 TypeScript 的类型推断和控制流分析也是非常有帮助的。