跳至主要內容

类型系统层级

linwu大约 4 分钟

类型系统层级

TypeScript 的类型系统是强类型和静态类型的,这为开发者提供了强大的类型检查和类型安全保障,同时也增加了一定的学习复杂性。为了更好地理解 TypeScript 的类型系统,本文将全面介绍其类型系统层级,包括顶层类型(Top Type)和底层类型(Bottom Type),以及在这个层次结构中如何处理和操作各种类型。理解 TypeScript 的类型系统层级有助于我们更好地使用和掌握 TypeScript,写出更健壮、可维护的代码。

1. 顶层类型(Top Type)

顶层类型是所有其他类型的父类型,这意味着在 TypeScript 中的任何类型都可以看作是顶层类型的子类型。TypeScript 中有两个特殊的顶层类型:anyunknown

1.1 any 类型

any类型是 TypeScript 的一个逃生窗口,它可以接受任意类型的值,并且对 any 类型的值进行的任何操作都是允许的。使用 any 类型,可以使我们绕过 TypeScript 的类型检查。

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) {}
}

在上面的代码中,函数 errorinfiniteLoop 的返回类型都是 never,这是因为这两个函数都永远不会有返回值。

3. 对比:顶层类型 vs 底层类型

顶层类型和底层类型是 TypeScript 类型系统的两个重要组成部分,它们各自扮演着不同的角色。

顶层类型 anyunknown 能够接受任何类型的值,这使得我们可以灵活地处理不确定类型的数据。然而,any 类型和 unknown 类型在使用上有着重要的区别:any 类型允许我们对其进行任何操作,而 unknown 类型则要求我们在操作之前进行类型检查或类型断言,以确保类型的安全性。

底层类型 never 有点特殊,它表示一个永远不会有值的类型。在实际开发中,我们可能很少直接使用 never 类型,但是它在 TypeScript 的类型推断和控制流分析中起着非常重要的作用。

理解 TypeScript 的类型系统层级有助于我们编写更健壮、可维护的 TypeScript 代码。尽管 any 类型提供了很大的灵活性,但是它的滥用可能会削弱 TypeScript 的类型安全性。因此,我们应尽量避免使用 any 类型,而优先使用 unknown 类型和类型断言、类型保护等方式来处理不确定类型的数据。同时,虽然我们可能很少直接使用 never 类型,但是理解它的含义和用法,对于我们理解 TypeScript 的类型推断和控制流分析也是非常有帮助的。

关注公众号

和小伙伴们一起学习

加入技术交流群

扫描二维码 备注加群