TypeScript 学习笔记(三):any,unknown和never。

前言

在上一篇文章TypeScript 学习笔记(二):基础类型中,我们简单的学习了TS中的一些基础的类型,但是TS除了基础的类型,还有很多种类型。本篇文章我们学习下TS中的三种特殊类型

any 类型

基本含义

any 类型表示没有任何限制,该类型的变量可以赋予任意类型的值。

TS 复制代码
let x:any;

x = 1; // 正确
x = 'foo'; // 正确
x = true; // 正确

上面示例中,变量x的类型是any,就可以被赋值为任意类型的值。

变量类型一旦设为any,TypeScript 实际上会关闭这个变量的类型检查。即使有明显的类型错误,只要句法正确,都不会报错。

TS 复制代码
let x:any = 'hello';

x(1) // 不报错
x.foo = 100; // 不报错

上面示例中,变量x的值是一个字符串,但是把它当作函数调用,或者当作对象读取任意属性,TypeScript 编译时都不报错。原因就是x的类型是any,TypeScript 不对其进行类型检查。

使用场景

any类型主要适用以下两个场合。

  • 由于一些原因,需要关闭某些变量的类型检查,就可以把该变量的类型设为any

  • 为了适配以前老的JS项目,让代码迁移到TS,可以把变量类型设为any

有些年代很久的大型JS项目,尤其是别人的代码,很难为每一行适配正确的类型,这时你为那些类型复杂的变量加上anyTS编译时就不会报错。

总之,TypeScript 认为,只要开发者使用了any类型,就表示开发者想要自己来处理这些代码,所以就不对any类型进行任何限制,怎么使用都可以。

从集合论的角度看,any类型可以看成是所有其他类型的全集,包含了一切可能的类型。TypeScript 将这种类型称为"顶层类型"(top type),意为涵盖了所有下层。

any的类型推断问题

对于开发者没有指定类型、TS会自己推断类型,如果无法推断出类型,就会认为该变量的类型是any

TS 复制代码
function add(x, y) {
  return x + y;
}

add(1, [1, 2, 3]) // 不报错

上面示例中,函数add()的参数变量xy,都没有足够的信息,TS无法推断出它们的类型,就会认为这两个变量和函数返回值的类型都是any

any的污染问题

any类型除了关闭类型检查,还有一个很大的问题,就是它会"污染"其他变量。 它可以赋值给其他任何类型的变量(因为没有类型检查),导致其他变量出错。

TS 复制代码
let x:any = 'hello';
let y:number;

y = x; // 不报错

y * 123 // 不报错
y.toFixed() // 不报错

unknown 类型

为了解决any类型"污染"其他变量的问题,TypeScript 3.0 引入了unknown类型。

它与any含义相同,表示类型不确定,可能是任意类型,但是它的使用有一些限制,不像any那样自由,可以视为严格版的any

unknownany的区别

相同点

  • unknownany的相似之处,在于所有类型的值都可以分配给unknown类型。
TS 复制代码
let x:unknown;

x = true; // 正确
x = 42; // 正确
x = 'Hello World'; // 正确

上面示例中,变量x的类型是unknown,可以赋值为各种类型的值。这与any的行为一致。

不同点

  • unknown类型跟any类型的不同之处在于,它不能直接使用。

-unknown类型的变量,不能直接赋值给其他类型的变量(除了any类型和unknown类型)。

TS 复制代码
let v:unknown = 123;

let v1:boolean = v; // 报错
let v2:number = v; // 报错

上面示例中,变量vunknown类型,赋值给anyunknown以外类型的变量都会报错,这就避免了污染问题,从而克服了any类型的一大缺点。

  • 不能直接调用unknown类型变量的方法和属性。
TS 复制代码
let v1:unknown = { foo: 123 };
v1.foo  // 报错

let v2:unknown = 'hello';
v2.trim() // 报错

let v3:unknown = (n = 0) => n + 1;
v3() // 报错

上面示例中,直接调用unknown类型变量的属性和方法,或者直接当作函数执行,都会报错。

  • unknown类型变量能够进行的运算是有限的,只能进行比较运算(运算符=====!=!==||&&?)、取反运算(运算符!)、typeof运算符和instanceof运算符这几种,其他运算都会报错。
TS 复制代码
let a:unknown = 1;

a + 1 // 报错
a === 1 // 正确

上面示例中,unknown类型的变量a进行加法运算会报错,因为这是不允许的运算。但是,进行比较运算就是可以的。

总之,unknown可以看作是更安全的any。一般来说,凡是需要设为any类型的地方,通常都应该优先考虑设为unknown类型。

在集合论上,unknown也可以视为所有其他类型(除了any)的全集,所以它和any一样,也属于 TypeScript 的顶层类型。

never 类型

TS引入了"空类型"的概念,即该类型为空,不包含任何值。该类型被称为never

TS 复制代码
let x:never;

上面示例中,变量x的类型是never,就不可能赋给它任何值,否则都会报错。 即使any也不可以赋值给never

主要使用场景

如果一个变量为联合类型,通常需要处理每一种类型。这时,处理所有可能的类型之后,剩余的情况就属于never类型。

TS 复制代码
function fn(x:string|number) {
  if (typeof x === 'string') {
    // ...
  } else if (typeof x === 'number') {
    // ...
  } else {
    x; // never 类型
  }
}
相关推荐
AverageJoe199122 分钟前
一次vite热更新不生效问题排查
前端·debug·vite
努力只为躺平24 分钟前
🔥 油猴脚本开发指南:从基础API到发布全流程
前端·javascript
bitbitDown25 分钟前
我用Playwright爬了掘金热榜,发现了这些有趣的秘密... 🕵️‍♂️
前端·javascript·vue.js
陈随易29 分钟前
VSCode v1.102发布,AI体验大幅提升
前端·后端·程序员
ma7734 分钟前
JavaScript 获取短链接原始地址的解决方案
前端
该用户已不存在34 分钟前
关于我把Mac Mini托管到机房,后续来了,还有更多玩法
服务器·前端·mac
tianchang37 分钟前
SSR 深度解析:从原理到实践的完整指南
前端·vue.js·设计模式
闲蛋小超人笑嘻嘻38 分钟前
前端面试十一之TS
前端
摆烂为不摆烂38 分钟前
😁深入JS(四): 一文让你完全了解Iterator+Generator 实现async await
前端
DoraBigHead1 小时前
🧠 别急着传!大文件上传里,藏着 Promise 的高级用法
前端·javascript·面试