【ArchSummit架构师峰会】探讨数据与人工智能相互驱动的关系>>> 了解详情
写点什么

TypeScript 3.6 正式发布!新增 4 项突破性特点

  • 2019-09-03
  • 本文字数:6151 字

    阅读完需:约 20 分钟

TypeScript 3.6正式发布!新增4项突破性特点

8 月 28 日微软正式发布了 TypeScript 3.6 版,本文将主要介绍 TypeScript 3.6 版中的更新内容,包括:语言和编译器、新的 TypeScript Playground、编辑功能等。​


我们很高兴地宣布,TypeScript 3.6 正式面世了!


有些人可能还不太了解 TypeScript,这里做一个简单介绍:TypeScript 是一种基于 JavaScript 的语言,在后者的基础上添加了可选的静态类型;TypeScript 编译器可以检查这些类型以捕获程序中的常见错误(例如属性拼写错误和函数调用错误等);然后可以使用 TypeScript 编译器和 Babel 等工具将基于最前沿规范编写的 TypeScript 代码转换为符合标准的 ECMAScript 代码,后者可在任何浏览器或运行时(甚至是只支持 ES3 或 ES5 的旧版本)上运行。


TypeScript 不仅具备类型检查和较新的 ECMAScript 功能,其编辑工具也是业界一流水平,是 TypeScript 项目不可或缺的一部分;多种类型的编辑器为 TypeScript 提供了代码自动完成、重构和快速修复等功能。如果你在 Visual Studio 或 Visual Studio Code 中编辑过 JavaScript 文件,其实这些体验是由 TypeScript 提供的,所以你可能已经在不知情的情况下开始使用 TypeScript 了!


你可以查看TypeScript官方网站了解更多信息。TypeScript 可以通过NuGet获取,或在 npm 中键入以下命令:


npm install -g typescript
复制代码


可选的编辑器有:



不久的将来我们还会提供其他编辑器的支持


下面来看看 3.6 版中的更新内容吧!

语言和编译器

更严格的生成器

TypeScript 3.6 对迭代器和生成器函数的检查更严格了。在早期版本中,用户使用生成器时无法判断一个值是从生成器 yield 还是返回的。


function* foo() {    if (Math.random() < 0.5) yield 100;    return "Finished!"}
let iter = foo();let curr = iter.next();if (curr.done) { // TypeScript 3.5及之前版本把它当成 'string | number'. // 它应该知道这是 'string' ,因为 'done' 是 'true'! curr.value}
复制代码


此外,生成器之前会假定 yield 的类型总是 any。


function* bar() {    let x: { hello(): void } = yield;    x.hello();}
let iter = bar();iter.next();iter.next(123); // oops! runtime error!
复制代码


TypeScript 3.6 中的检查器现在知道第一段代码中的 curr.value 的正确类型应该是 string,并且在第二段代码中调用 next()时会正确地报错。这是因为 Iterator 和 IteratorResult 类型声明中现在引入了一些新的类型参数,且新版 TypeScript 会用 Generator 这个新类型来表示生成器。


Iterator 类型现在允许用户指定 yield 类型、返回的类型以及 next 可以接受的类型。


interface Iterator<T, TReturn = any, TNext = undefined> {    // 接收 0 或 1 参数 - 不接收 'undefined'    next(...args: [] | [TNext]): IteratorResult<T, TReturn>;    return?(value?: TReturn): IteratorResult<T, TReturn>;    throw?(e?: any): IteratorResult<T, TReturn>;}
复制代码


在此基础上,新的 Generator 类型是一个 Iterator,它总是同时存在 return 和 throw 方法,并且也是可迭代的。


interface Generator<T = unknown, TReturn = any, TNext = unknown>        extends Iterator<T, TReturn, TNext> {    next(...args: [] | [TNext]): IteratorResult<T, TReturn>;    return(value: TReturn): IteratorResult<T, TReturn>;    throw(e: any): IteratorResult<T, TReturn>;    <a href="">Symbol.iterator: Generator<T, TReturn, TNext>;}</a href="">
复制代码


为了区分返回值和生成值,TypeScript 3.6 将 IteratorResult 类型转换为差别联合类型:


type IteratorResult<T, TReturn = any> = IteratorYieldResult<T> | IteratorReturnResult<TReturn>;
interface IteratorYieldResult<TYield> { done?: false; value: TYield;}
interface IteratorReturnResult<TReturn> { done: true; value: TReturn;}
复制代码


简而言之,这意味着你在直接处理迭代器时能够适当地缩小迭代器的值。


为了正确表示可以从调用 next()传递给生成器的类型,TypeScript 3.6 还可以在生成器函数主体内推断出某些 yield 用法。


function* foo() {    let x: string = yield;    console.log(x.toUpperCase());}
let x = foo();x.next(); // 对 'next' 的第一个调用都会被忽略x.next(42); // error! 'number' 无法被分配给 'string'
复制代码


如果你更喜欢显式方法,那么还可以强制可以用 yield 表达式执行返回、yield 和计算的值的类型使用显式返回类型。下面的例子中,next( )只能用布尔值调用,并且根据 done 的值,value 可以是 string 或 number。


/** * - yields numbers * - returns strings * - can be passed in booleans */function* counter(): Generator<number, string, boolean> {    let i = 0;    while (true) {        if (yield i++) {            break;        }    }    return "done!";}
var iter = counter();var curr = iter.next()while (!curr.done) { console.log(curr.value); curr = iter.next(curr.value === 5)}console.log(curr.value.toUpperCase());
// prints://// 0// 1// 2// 3// 4// 5// DONE!
复制代码


这部分更改的详情可参阅github

更准确的数组扩展

在目标为 ES2015 之前的版本中,诸如 for/of 循环和数组扩展之类的结构用的发射有些复杂。因此 TypeScript 默认使用更简单的发射,只支持数组类型,并支持使用–downlevelIteration 标志在其他类型上迭代。在此标志下发出的代码更准确,但体积也大得多。


默认情况下–downlevelIteration 是关闭的,因为以 ES5 为目标的用户多数只使用带数组的迭代结构。但某些边缘情况下只支持数组的发射还是有一些可见的差异。


例如,以下示例


[...Array(5)]
复制代码


等同于下列数组:


[undefined, undefined, undefined, undefined, undefined]
复制代码


但是,TypeScript 会将原始代码转换为下面的代码:


Array(5).slice();
复制代码


它们是有些不一样的。Array(5)生成一个长度为 5 的数组,但没有定义的属性槽!


1 in [undefined, undefined, undefined] // true1 in Array(3) // false
复制代码


当 TypeScript 调用 slice()时,它还会创建一个其索引尚未设置的数组。


这可能不太好理解,但其实有许多用户遇到了这种麻烦。TypeScript 3.6 不再使用 slice()和内置函数,而是引入了一个新的__spreadArrays助手,将 ECMAScript 2015 的内容在较旧的目标中模拟出来,不用 --downlevelIteration。 __spreadArrays 也可以在tslib中使用(如果你想缩小包的体积,那么非常值得一试)。


有关更多信息,请参阅资料

改进了 Promise 相关的用户体验

Promise 是当今最常用的异步数据方法之一。然而面向 Promise 的 API 通常会让用户感到困惑。TypeScript 3.6 引入了一些改进,避免用户错误处理 Promise。


例如,在将 Promise 的内容传递给另一个函数之前,人们往往会忘记.then()或 await 这部分内容。TypeScript 现在有了对应的错误消息,并告知用户他们可能应该使用 await 关键字。


interface User {    name: string;    age: number;    location: string;}
declare function getUserData(): Promise<User>;declare function displayUser(user: User): void;
async function f() { displayUser(getUserData());// ~~~~~~~~~~~~~// 类型 'Promise<User>' 的参数不能分配给类型 'User'的参数.// ...// Did you forget to use 'await'?}
复制代码


在 await 或.then()一个 Promise 之前就尝试访问方法也是很常见的错误。这类错误很多,我们都做了改进。


async function getCuteAnimals() {    fetch("https://reddit.com/r/aww.json")        .json()    //   ~~~~    // 属性 'json' 在类型 'Promise<Response>'上不存在.    //    // Did you forget to use 'await'?}
复制代码


这里的目的是就算用户没意识到要 await,起码这些消息能给出一些提示。


除了改进 Promise 相关的错误消息外,我们现在还在某些情况下提供了快速修复。



有关更多详细信息,请参阅原始问题及相关链接。

对标识符的 Unicode 支持改进

当发射到 ES2015 及更高版本的目标时,TypeScript 3.6 对标识符的 Unicode 字符提供了更好的支持。


const 𝓱𝓮𝓵𝓵𝓸 = "world"; // 以前不允许, 现在对 '--target es2015' 允许
复制代码

SystemJS 中的 import.meta 支持

当 module 目标设置为 system 时,TypeScript 3.6 支持将 import.meta 转换为 context.meta。


// 这个模块:
console.log(import.meta.url)
// 被改成:
System.register([], function (exports, context) { return { setters: [], execute: function () { console.log(context.meta.url); } };});
复制代码

在环境上下文中允许 get 和 set 访问器

以前的 TypeScript 版本不允许在环境上下文中 get 和 set 访问器(例如在 declare-d 类中,或者在.d.ts 文件中)。理由是对于这些属性的读写而言访问器与属性没有区别;但是因为 ECMAScript 的类字段提案可能与现有 TypeScript 版本中的行为不同,我们意识到我们需要一种方法来对接这种行为差异,以便在子类中提供适当的错误。


因此,用户现在可以在 TypeScript 3.6 的环境上下文中编写 getter 和 setter。


declare class Foo {    // 在 3.6+ 版本中允许.    get x(): number;    set x(val: number): void;}
复制代码


在 TypeScript 3.7 中编译器也将利用此功能,以便生成的.d.ts 文件也发射 get/set 访问器。

环境类和函数可以合并

在以前版本的 TypeScript 中,任何情况下合并类和函数都是错误的。现在环境类和函数(具有 declare 修饰符或在.d.ts 文件中的类/函数)可以合并了。这意味着现在你可以编写以下代码:


export declare function Point2D(x: number, y: number): Point2D;export declare class Point2D {    x: number;    y: number;    constructor(x: number, y: number);}
复制代码


这样就用不着再写成:


export interface Point2D {    x: number;    y: number;}export declare var Point2D: {    (x: number, y: number): Point2D;    new (x: number, y: number): Point2D;}
复制代码


这样做的一个优点是可以很容易地表达可调用的构造函数模式,同时还允许名称空间与这些声明合并(因为 var 声明不能与 namespace 合并)。


在 TypeScript 3.7 中,编译器也将利用此功能,以便从.js 文件生成的.d.ts 文件可以正确捕获类函数的可调用性和可构造性。


更多详细信息请参阅 GitHub 上的原始PR

为–build 和–incremental 提供 API 支持

TypeScript 3.0 开始支持引用其他项目,并使用–build 标志以增量方式构建它们。之后 TypeScript 3.4 引入了–incremental 标志来保存之前编译的相关信息,这样就可以只重建特定文件了。这些标志可以帮助用户更快、灵活地构建项目。可惜这些标志无法用于 Gulp 和 Webpack 这样的第三方构建工具。TypeScript 3.6 现在公开了两组 API 来处理项目引用和增量程序构建。


创建–incremental 构建时用户可以利用 createIncrementalProgram 和 createIncrementalCompilerHost API。用户还可以使用新公开的 readBuilderProgram 函数从这个 API 生成的.tsbuildinfo 文件中重新保存旧程序实例,该函数仅用于创建新程序(你无法修改返回的实例,它仅用于其他 create*Program 函数中的 oldProgram 参数)。


针对项目引用方面,新版引入了一个新的 createSolutionBuilder 函数,它返回一个新类型 SolutionBuilder 的实例。


有关这些 API 的详细信息可参阅资料

新的 TypeScript Playground

应用户呼吁,新版 TypeScript Playground 做了大幅改进,引入了许多全新功能。新版 Playground 基本上是社区流行的Artem TyurinTypeScript Playground的一个 fork。我们在这里非常感谢 Artem 提供的帮助!


新版 Playground 提供了许多新选项,包括:


  • target 选项(允许用户从 es5 切换到 es3、es2015、esnext 等)

  • 所有严格标志(包括 strict)

  • 支持纯 JavaScript 文件(使用 allowJS 和可选的 checkJs)


这些选项在共享 Playground 样本时也能使用,让用户可以更可靠地共享示例,无需告诉收件人“哦,别忘了打开 noImplicitAny 选项!”。


在不久的将来,我们将改进 Playground 样本功能、添加 JSX 支持、改进自动类型获取等,让用户使用 Playground 时如同在使用自己的编辑器一样。


我们欢迎大家在GitHub上提交反馈和请求!

编辑功能

分号感知代码编辑

Visual Studio 和 Visual Studio Code 等编辑器可以自动应用快速修复、重构、自动从其他模块导入值等转换。这些转换由 TypeScript 提供支持,而旧版本的 TypeScript 会无条件地在每个语句的末尾添加分号;但很多用户不喜欢这种风格,不希望编辑器自动插入分号。


TypeScript 现在变得非常聪明,可以在应用这些编辑时检测你的文件是否使用分号。如果你的文件不怎么用分号的话 TypeScript 也不会添加分号。


更多详细信息请参阅资料

更智能的自动导入

JavaScript 有许多不同的模块语法或约定:ECMAScript 标准是一种、Node 支持的一种(CommonJS)、AMD 一种、System.js 又是一种,还有更多!在大多数情况下 TypeScript 默认使用 ECMAScript 模块语法来自动导入,遇到有些使用不同编译器设置的 TypeScript 项目就不怎么合适,在使用纯 JavaScript 和 require 调用的 Node 项目中也不搭配。


TypeScript 3.6 变得更聪明了一些,可以先查看你现有的导入后再决定怎样自动导入其他模块。你可以在此处查看更多信息

重大更新

命名为“constructor”的类成员现在是构造函数

根据 ECMAScript 规范,使用名为 constructor 的方法的类声明现在是构造函数,无论它们是使用标识符名称还是字符串名称声明都是如此。


class C {    "constructor"() {        console.log("我是构造函数.");    }}
复制代码


注意有一个例外,就是计算属性的名称等于“constructor”的情况。


class D {    <a href="">"constructor" {        console.log("我不是一个构造函数 - 只是一个方法");    }}</a href="">
复制代码

DOM 更新

新版 lib.dom.d.ts 中的许多声明已被删除或更改。具体包括(但不限于)以下内容:


  • 全局 window 不再定义为类型 Window——而是将其定义为类型 Window&typeof globalThis。在某些情况下,最好将其类型称为 typeofwindow。

  • GlobalFetch 已经移除了,取而代之的是 WindowOrWorkerGlobalScope。

  • Navigator 上的某些非标准属性消失了。

  • experimental-webgl 上下文移除了。替代品是 webgl 或 webgl2。

JSDoc 注释不再合并

在 JavaScript 文件中,TypeScript 只会在 JSDoc 注释之前确定声明的类型。


/** * @param {string} arg *//** * oh, hi, were you trying to type something? */function whoWritesFunctionsLikeThis(arg) {    // 'arg' has type 'any'}
复制代码

关键字不能包含转义序列

以前关键字允许包含转义序列。TypeScript 3.6 中就不行了。


while (true) {    \u0063ontinue;//  ~~~~~~~~~~~~~//  error! Keywords cannot contain escape characters.}
复制代码

未来计划

想要了解官方团队未来要开展的工作,请查看今年 7 月至 12 月的半年路线图计划


我们希望这个新版本能继续改善你的开发体验。你有任何建议或遇到任何问题我们都很感兴趣,欢迎大家在GitHub上提交反馈。


英文原文:https://devblogs.microsoft.com/typescript/announcing-typescript-3-6/


2019-09-03 08:205985

评论

发布
暂无评论
发现更多内容

如何设置Activity背景颜色与ProgressBar进度条颜色

Changing Lin

12月日更

如何更快上手使用 OceanBase 社区版?

OceanBase 数据库

数据库 直播 课程 OceanBase 开源

PackML从会到不会——标签(3)

陈的错题集

标准化 PackML

用户登录设计之双token设计

CRMEB

语法糖甜不甜?巧用枚举实现“状态”转换限制

阿Q说代码

枚举 签约计划第二季 语法糖 订单状态转换

秒过!度目智慧通行让常态化防疫更高效

百度开发者中心

人工智能

「Spark从精通到重新入门(一)」Spark 中不可不知的动态优化

尔达Erda

云计算 大数据 spark 开发者 感悟

四步做好Code Review

百度开发者中心

Code Review

实战篇:断点续传?文件秒传?手撸大文件上传

阿Q说代码

断点续传 签约计划第二季 文件秒传 文件分块 文件合并

长连接网关技术专题(六):石墨文档单机50万WebSocket长连接架构实践

JackJiang

websocket 即时通讯 IM 网关

秒过!度目智慧通行让常态化防疫更高效

百度大脑

人工智能 人脸识别

后端开发实战总结 | 签约计划第二季|后端

阿Q说代码

内容合集 签约计划第二季 技术专题合集

WeTest小程序质量专项方案推出,小程序异常监控内测招募中

WeTest

【量化】股市技术分析利器之TA-Lib(二)

恒生LIGHT云社区

量化投资 量化

Linux学习方法《Linux一学就会》Linux系统进程管理

侠盗安全

Linux linux运维 运维工程师 云计算架构师

IoT Stack 2.0升级物模型及数据交互协议, 大幅提升物联网方案交付速度

百度大脑

人工智能 百度 物联网

看了这么多年西游记,你可知道孙悟空是如何召唤土地公公的吗?

阿Q说代码

Java 观察者模式 签约计划第二季 事件通知机制

『上线』OpenSEC SIGs 终于成立了!

SphereEx

开源社区 ShardingSphere SphereEx 中文开源 OpenSEC

ZEGO 即构科技首发适配鸿蒙系统的 Express SDK 1.0 版本,并正式启动公测!(内附源码)

ZEGO即构

音视频 HarmonyOS 鸿蒙开发 即构科技

科技热点周刊|PHP 基金会成立、Rust 内讧、Amazon Linux 2022 预览版发布

青云技术社区

云计算

大规模 K8s 集群管理经验分享 · 上篇

尔达Erda

程序员 云原生 k8s K8s 多集群管理 经验分享、

实战篇:Security+JWT组合拳 | 附源码

阿Q说代码

spring security JWT 签约计划第二季 权限验证

恒源云(GPUSHARE)_GPU白嫖大法来袭!

恒源云

深度学习 gpu 算力加速

【量化】股市技术分析利器之TA-Lib(一)

恒生LIGHT云社区

量化投资 量化

博文推荐|使用 Pulsar IO 打造流数据管道

Apache Pulsar

Java 开源 架构 云原生 Apache Pulsar

看了同事写的代码,我竟然开始默默的模仿了。。。

阿Q说代码

策略模式 多态 签约计划第二季 自定义参数解析器 统一验签

如果还不懂如何使用 Consumer 接口,来公司我当面给你讲!

阿Q说代码

函数式接口 签约计划第二季 consumer 实战讲解 supplier

Spark从入门到精通

冇先生

高校企业双向赋能,首届飞桨启航菁英计划圆满结束

百度大脑

人工智能 百度 飞桨

【活动报名】Apache ShardingSphere Dev Meetup 重启!

SphereEx

开源项目 开源社区 ShardingSphere Meetup SphereEx

还在用BeanUtils拷贝对象?MapStruct才是王者!【附源码】

阿Q说代码

Java MapStruct 签约计划第二季 深拷贝与浅拷贝

TypeScript 3.6正式发布!新增4项突破性特点_语言 & 开发_Daniel Rosenwasser_InfoQ精选文章