前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >[译] TypeScript4有些啥?

[译] TypeScript4有些啥?

作者头像
腾讯IVWEB团队
发布2020-07-01 11:24:05
9430
发布2020-07-01 11:24:05
举报
文章被收录于专栏:腾讯IVWEB团队的专栏

原文: What's coming in TypeScript 4 作者: Tim Perry

TypeScript4来得很快, 这周(6.25)就有一个Beta Release的计划, 而最终的正式release将会在八月中旬到来.

需要注意的是, TypeScript的Release并没有遵循Semantic版本规则进行, 所以4.0版本并不算是一个大型的更新.

TypeScript never claimed to follow semantic versioning, in the sense that breaking changes imply major versions. TypeScript, however, promises no breaking changes after a stable release. so no breaking changes between 2.1.5 and 2.1.6, 2.1.*. TypeScript从来没有说过遵循Semantic版本规则, 即断代更新会体现在主版本号变更上相反, TypeScript承诺在每一个Stable Release之间不会有断代更新, 因此在2.1.5, 2.1.6, 2.1.*...上面不存在断代更新

版本号跳到了4.0并不意味着这里有什么大型的断代, 这不是啥改变一切的Release, 但他还是确确实实带来了一些关于类型的棒棒的改动. 对于像HTTP Toolkit(完全是TypeScript开发的)的项目来说, 这次改动能够带来更快的开发速度以及更少的bug.

让我们来深入一下细节的部分.

可变元组类型 Variadic Tuple Type

所谓"可变类型", 对于TypeScript的类型系统来说, 是一个复杂但是颇具重要性的新Feature.

如果没有深刻理解类型理论的话, 解释这玩意儿会有点麻烦, 但是举个例子还是很简单的. 让我们试试用元组参数来书写一个concat函数:

代码语言:javascript
复制
function concat(
    nums: number[],
    strs: string[]
): (string | number)[] {
    return [...nums, ...strs];
}

let vals = concat([1, 2], ["hi"]);
let val = vals[1]; // 尽管我们知道这是一个number, 但TS仍然会提示这是一个number|string

// 但TS确实支持对这些值的精确的类型定义
let typedVals = concat([1, 2], ["hi"]) as [number, number, string];
let typedVal = typedVals[1] // => 提示number, 没问题

在目前, 这段代码是合法的TS代码, 但并不是最优的.

这段代码中, concat能够正确地起作用, 但是我们会丢失一些类型, 而且如果想要在其他地方获得精确的类型的话, 就不得不在之后手动地进行修正. 目前还没有可能能够完全避免这些问题.

在有了可变元组之后, 我们可以这样写

代码语言:javascript
复制
function concat<N extends number[], S extends string[]>(
    nums: [...N],
    strs: [...S]
): [...N, ...S] {
    return [...nums, ...strs];
}

let vals = concat([1, 2], ["hi"]);
let val = vals[1]; // => 提示类型 number
const val2 = vals[1]; // => 提示值 2, 而不只是类型number

// 在深入一点, 我们可以精确地concat任何类型
function concat<T extends unknown[], U extends unknown[]>(
    t: [...T],
    u: [...U]
): [...T, ...U] {
    return [...t, ...u];
}

本质上来说, 元组类型现在能够包含...T作为一个多个元组内类型的泛型占位. 可以通过此来形容一些未知类型([...T]), 或者部分类型已知的元组([string, ...T, boolean, ...U]).

TypeScript能够在之后使用的过程中提示这些类型, 因此只需要在大体地对元组形状进行描述并在之后使用, 而不需要依赖具体的细节.

这是一种相对简洁的方式, 并且比简单地连接数组要来的更为广泛. 通过组合一些已经存在的可变函数, 例如f<T extends unknown[]>(...args: [...T]), 就能够把函数的参数当做数组来看待, 进而能够比现在更具弹性地去描述函数的参数格式.

举个例子, 目前对函数中剩余/可变参数的描述必须始终放在函数参数描述的末尾, f(a: number, ...b:string[], c: boolean)便是一个无效的例子

在这一次的升级之后, 通过在函数参数定义中使用可变元组类型, f<T extends string[]>(...args: [number, ...T, boolean])便能使上述的例子成为可能

看起来有点抽象, 实际上可以这么理解, 我们能通过这一特性来做到:

  • 解构数组类型: type head = <H extends unkone, T extends unknonw[]>(list: [H, ...T]) => H
  • 对任意长度的数组执行类似映射类型才允许的操作, 而不仅仅是对象
  • 对可变参数的函数进行完整的类型提示
  • 对复杂的, 部分参数类型已知的可变参数进行正确的提示
  • 对Promisify进行完整的类型定义
  • 对诸如curry, apply, compose等高阶函数进行完整地参数类型描述
  • 干掉所有的为了完整描述类型而产生的冗余代码.

就算现在没在写什么复杂的高阶函数, 改进类型也仍然能让我们在之后的能够更细节地去描述类型, 正确提示一些不明确的数组类型定义, 改进其他地方的类型提示.

带标注的元组 Labelled Tuples

这是一个跟上一个有关系, 但是要简单得多的特性: TypeScript将允许给元组中的元素加上标注了.

看看下面这个函数的类型的描述, 你能从中获得什么信息?

代码语言:javascript
复制
function getSize(): [number, number];

那这个呢

代码语言:javascript
复制
function getSize(): [min: number, max: number];

这些标注会在运行时消失(编译时会被注释掉), 并且也不会做额外的类型检查. 它们能像上面那样使得元组的声明变得更加直观清晰.

对于剩余/可选参数同样适用:

代码语言:javascript
复制
type MyTuple = [a: number, b?: number, ...c: number[]];

从构造函数的使用来推断属性类型

一个简明的类型提示的改进

代码语言:javascript
复制
class X {

    private a;

    constructor(param: boolean) {
        if (param) {
            this.a = 123;
        } else {
            this.a = false;
        }
    }

}

在上面这段代码中, 目前的TS版本中, a会被认为是any的类型(甚至还会在noImplicitAny开启时报错). 属性的类型只会在直接初始化的时候得到推断. 因此需要一个初始化函数, 或者直接对其进行定义.

在TypeScript4中, a的类型会被推断为number | boolean: 从构造函数自动推断.

如果这种机制还不能满足, 仍然能够通过精准定义的方式来对属性进行类型声明, 并且当这类声明存在时, 他们会被更优先地使用.

短路赋值操作符

对类型方面的改进不感兴趣? 没问题, TypeScript4.0同时实现了处于Stage3的JS特性: 逻辑运算赋值. 新的语法得到支持, 并会被编译到老的环境中也能运行的形式.

看起来就像这样

代码语言:javascript
复制
a ||= b
// 等于: a = a || b

a &&= b
// 等于: a = a && b

a ??= b
// 等于: a = a ?? b

目前, 最后一个选项可能是最有用的, 除非正儿八经地在进行布尔运算, 那这个合并运算对于默认值和错误回落值是个很完美的解决方案.

一些其他的部分

上面都是些主要的改动, 下面是一些其他的也很不错的部分:

  • unknown现在能够做为try..catch...中的类型标注 try {...} catch (e: unknown) {...}
  • 支持了React的新的JSX内部(译注: children之类的)
  • 编辑器对@deprecatedJSDoc注解的支持
  • 在3.9版本的性能提升后的性能提升
  • 新的编辑器可用的代码重构(比如自动的用可选链Optional Chaining进行重构), 改进了一些重构(更好的auto-import), 以及一些语法高亮

上述这些改动都不是大型的改动, 但也值得重视. 至少它们帮着TypeScript的程序员们续命了 -- 改善了类型安全以及开发体验.

当然需要注意的是, 这些并不是最终敲定的改动, 文章跳过一些讨论过但并没有被实现的特性, 从awaited T到占位符类型(这些特性可能下个月突然就冒出来了), 并且上面这些已经实现了的特性中也有可能因为一些不可避免的因素发生改变之类的. 所以要保持关注...

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 可变元组类型 Variadic Tuple Type
  • 带标注的元组 Labelled Tuples
  • 从构造函数的使用来推断属性类型
  • 短路赋值操作符
  • 一些其他的部分
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档