TypeSript 5.2 有哪些新特性 - Union类型的方法调用问题


咱们在讲这次TypeScript 5.2 的新特性前先介绍一下Union联合类型,这样大家了解事情的前因后果后,就更容易理解这次的新特性了。如果你对这个类型很了解,可以直接看最后一部分。 ## 什么是Union类型 当一个变量有可能有多种类型时,可以把这些类型组合在一起,来给这个变量进行类型定义,这个组合起来的类型就是Union,中文可以叫联合。 具体形式如下: ``` typescript let id: number | string; ``` 这里的`number | string`就是Union联合类型,它代表`id`既可能是`number`类型,也可能是`string`类型。

Union联合类型的特性

可缩小类型范围

虽然一个变量有可能有多种类型,但是当具体执行使用到某个变量时,它的类型一定是确定的。

举例如下:

typescript 复制代码
function printId(id: number | string) {
  if (typeof id === "string") {
    // 这个分支中 id 的类型是 string
    console.log(id.toUpperCase());
  } else {
    // 这个分支中 id 的类型是 number
    console.log(id);
  }
}

上面的例子中,id既有可能是number,又可能是string,但是经过typeof的判断后,可以确定if中的一定是stringelse中的一定是number。 如果你用VSCode的话,在if分支中,它可以正确的提示出所有String暴露的属性和方法,而不会给出number的。

也就是说TypeScript会在编译器尽量的判断变量的真实类型,从而减少开发人员的低级错误。虽然是Union联合类型,但是只要是编译期可以确定最终具体类型,TypeScript一定会尽量确定下来。这就是所谓的"可缩小类型范围"。

可以使用共同的属性和方法

上面说到TypeScript会尽量帮开发人员缩小Union联合类型的范围,但是如果组成Union联合类型的子类型都具有相同签名的方法或者属性的话,那不需要缩小类型范围,就可以直接对Union类型的变量调用这些方法或者属性。 语言解释太抽象,咱们直接看例子:

typescript 复制代码
// 函数返回类型会被推断为:number[] | string
function getFirstThree(x: number[] | string) {
  // slice是number和string都有的方法
  return x.slice(0, 3);
}

上面例子中参数x既有可能是number[],也有可能是string。它们有一个签名相同的方法slice。因此就可以直接调用slice。所谓签名相同就是:方法名字、参数类型、返回值类型都相同。 这时的返回值类型也是一个Union联合类型:number[] | string

这确实给开发带来了方便。 但是有一种情况,即使它们有相同的方法,也不能用。请往下看。

由数组组成的Union类型不能使用相同的方法

请看下面的例子:

typescript 复制代码
function filterOutInvalidItems(arr: number[] | string[]) {
	// 这里TypeScript会报错:联合类型的每个成员都有签名,但这些签名都不能互相兼容。ts(2349)
  	return arr.filter(x => !!x);
}

这里的arr是一个number数组和string数组的Union联合类型。按理说只要是数组的方法都可以直接使用,但是上面的例子中,filter却会报错:"联合类型的每个成员都有签名,但这些签名都不能互相兼容 ts(2349)"。 这是因为老版本的TypeScript对于不同类型数组的filter方法没有考虑一种将它们进行统一处理的策略,因此直接就报错了。

5.2 版本解决了这个问题

TypeScript 5.2 版本对于这种全部由数组组成的Union联合类型使用了一种新策略:将这种联合类型转成了数组。

拿上面的例子举例,5.2版本会先把Union联合类型number[] | string[]转成(number | string)[],这样两个数组类型合并成了一个数组类型,一切就变得简单了。 举例如下:

typescript 复制代码
function filterOutInvalidItems(arr: number[] | string[]) {
	// TypeScript 5.2 版本中这里不再报错
  	 let result = arr.filter(x: number | string => !!x);
	 // result的类型是(number | string)[],下面的赋值不会报错
	 retult = ['a', 9, 'b'];
	 return result;
}

上例中的x参数的类型变成了number | stringfilter的返回值类型也变成了(number | string)[]

不过这种处理策略其实会造成一些类型的不精准,因为最终filter的返回值类型和arr已经不一样了。数组类型的联合变成了联合类型的数组。还是有些美中不足。

总的一句话,现在新版本的TypeScript,对于这种数组类型的Union联合number[] | string[],可以使用filter find some every reduce等数组方法了,但是像fitler这种返回原数组部分内容的方法,其返回值的类型变成了联合类型的数组。

本篇到此结束。

相关推荐
敲敲了个代码20 小时前
从硬编码到 Schema 推断:前端表单开发的工程化转型
前端·javascript·vue.js·学习·面试·职场和发展·前端框架
dly_blog21 小时前
Vue 响应式陷阱与解决方案(第19节)
前端·javascript·vue.js
消失的旧时光-19431 天前
401 自动刷新 Token 的完整架构设计(Dio 实战版)
开发语言·前端·javascript
console.log('npc')1 天前
Table,vue3在父组件调用子组件columns列的方法展示弹窗文件预览效果
前端·javascript·vue.js
用户47949283569151 天前
React Hooks 的“天条”:为啥绝对不能写在 if 语句里?
前端·react.js
我命由我123451 天前
SVG - SVG 引入(SVG 概述、SVG 基本使用、SVG 使用 CSS、SVG 使用 JavaScript、SVG 实例实操)
开发语言·前端·javascript·css·学习·ecmascript·学习方法
用户47949283569151 天前
给客户做私有化部署,我是如何优雅搞定 NPM 依赖管理的?
前端·后端·程序员
C_心欲无痕1 天前
vue3 - markRaw标记为非响应式对象
前端·javascript·vue.js
qingyun9891 天前
深度优先遍历:JavaScript递归查找树形数据结构中的节点标签
前端·javascript·数据结构
熬夜敲代码的小N1 天前
Vue (Official)重磅更新!Vue Language Tools 3.2功能一览!
前端·javascript·vue.js