距离 typescript4.x 版本发布已经有一段时间,目前最新版本为 4.1.3。相较于 3.x 版本,4.x 又支持哪些新特性呢?

4.0 新特性:

可变元组类型

ts4 在 ts3 元组类型的基础上扩充了三点功能:

1.支持 spread 运算符在元组类型中作为泛型

通过这种方式,开发者可以定义元素类型不确定的数组或元组,同时编译器也可以自动推断出数组或元组的元素类型。

function tail(arr: readonly [any, ...T]) {

const [_ignored, ...rest] = arr;

return rest;

}

const myTuple = [1, 2, 3, 4] as const;

const myArray = ["hello", "world"];

// type [2, 3, 4]const r1 = tail(myTuple);

// type [2, 3, 4, ...string[]]const r2 = tail([...myTuple, ...myArray] as const);

2.spread 扩展的 rest 类型不必放到最后定义

ts4 中,可变元组类型不再要求 rest 类型放到最后定义。

type Strings = [string, string];

type Numbers = [number, number];

// [string, string, number, number, boolean]type StrStrNumNumBool = [...Strings, ...Numbers, boolean];

/*ts3 error 'A rest element must be last in a tuple type'!ts4 ok!*/

结合以上两点,开发者将不再需要编写繁琐的重载定义,以 function concat(arr1, arr2) {return [...arr1, ...arr2]} 函数为例:

在 ts3 中只能通过显示定义函数重载才能明确 concat 的返回值类型,无奈的是,这种做法无法罗列所有情况并不是一种通用实现。

function concat(arr1: [], arr2: [A2]): [A2];

function concat(arr1: [A1], arr2: [A2]): [A1, A2];

function concat(arr1: [A1, B1], arr2: [A2]): [A1, B1, A2];

function concat(arr1: [A1, B1, C1], arr2: [A2]): [A1, B1, C1, A2];

function concat(arr1: [A1, B1, C1, D1], arr2: [A2]): [A1, B1, C1, D1, A2];

function concat(arr1: [A1, B1, C1, D1, E1], arr2: [A2]): [A1, B1, C1, D1, E1, A2];

function concat(arr1: [A1, B1, C1, D1, E1, F1], arr2: [A2]): [A1, B1, C1, D1, E1, F1, A2];

更一般的做法是将 concat 定义为 function concat(arr1: T[], arr2: U[]): Array 但是对于编译器来说,它无法确认 concat 返回值数组长度和不同元素类型在数组中的位置。

有了可变元组类型以后,开发者只需简单几个语句便可定义出覆盖所有情况的 concat 类型,并且编译器可以精确推断出返回值数组长度和元素类型在数组中的位置。

type Arr = readonly any[];

function concat(arr1: [...T], arr2: [...U]): [...T, ...U] {

return [...arr1, ...arr2];

}

// type = [number, number, string, string]const arr = concat([1,2], ['hello', 'world'])

元组标签

ts4 带来的关于元组类型第三点变化是支持对元组类型打标签,类似于 js 中解构变量重命名。

type Range = [start: number, end: number];

type Foo = [first: number, second?: string, ...rest: any[]];

type Bar = [first: string, number]; // error! Tuple members must all have names or all not have names.

如果对元组类型打标签,则其中所有类型必须都标签化,不允许一部分类型标签化,一部分没有。

元组标签主要用于定义函数的入参,通过元组标签,编译器可以更好的提示函数入参类型

根据构造函数推断类属性类型

ts4 之前,如果不显示定义类属性的类型,编译器就会默认推断类属性类型为 any,ts4 开始,编译器可以通过开发者在构造函数中的赋值行为推断类属性的类型,前提是开启 noImplicitAny 选项 。

class Square {

area; // number sideLength; // number

constructor(sideLength: number) {

this.sideLength = sideLength;

this.area = sideLength ** 2;

}

}

短路运算符

在 +=,-=,*=,/= 等快捷运算式之外,ts4 还支持了 &&=,||=,??= 三个短路运算符,以 ||= 为例

obj.prop ||= foo();

// 等价于下面两种表达式 ,注意与 obj.prop = obj.prop || foo() 的区别 !!

obj.prop || (obj.prop = foo());

if (!obj.prop) {

obj.prop = foo();

}

catch 错误允许置为 unknown

在 ts4 之前,try/catch 捕获的异常被编译器视为 any 类型,然而 catch 内部的处理逻辑也可能产生非预期的错误,这就要求对 catch 捕获的异常有更严格的类型定义,ts4 允许将异常显示定义成 unknown 类型,开发者需进一步判断异常具体类型。

try {

// ...}

catch (e: unknown) {

// error! // Property 'toUpperCase' does not exist on type 'unknown'. console.log(e.toUpperCase());

if (typeof e === "string") {

// works! console.log(e.toUpperCase());

}

}

自定义 JSX 工厂函数

从 ts4 开始,通过新增的 jsxFragmentFactory 选项或内联的 @jsxFrag 注释,开发者可以自定义 jsx Fragment 语法的工厂函数, 如:

{

"compilerOptions": {

"target": "esnext",

"module": "commonjs",

"jsx": "react",

"jsxFactory": "h",

"jsxFragmentFactory": "Fragment"

}

}

/** @jsx h */

/** @jsxFrag Fragment */

import { h, Fragment } from "preact";

let stuff = <>

Hello

>;

/* 编译输出为import { h, Fragment } from "preact";let stuff = h(Fragment, null,h("div", null, "Hello"));*/

其他新特性--incremental 和 --noEmitOnError 同时开启时,会自动缓存前一次编译的错误到 .tsbuildinfo 文件

允许同时开启 --incremental 和 --noEmit

vscode 支持将条件判断表达式转为可选链式操作符vscode 支持提示 /** @deprecated */ 注释

vscode 支持对单份 ts 代码文件编译提速

vscode 支持更智能的自动导入

不兼容变化ts3 中当设置了 useDefineForClassFields 时,在继承类的过程中,不允许 getter/setter 属性和其他属性的互相覆盖,ts4 中不再需要设置 useDefineForClassFields,默认禁止互相覆盖

被 delete 的对象属性必须是可选的

ts4 前与 AST 节点相关的工厂函数被新的工厂函数所替代,老的完全被废弃

参考资料Announcing TypeScript 4.0 | TypeScript​devblogs.microsoft.com

-------------------------------------------------------------------------------------------

4.1 新特性:

模版字符串类型

es6 后新增了模版字符串,用户可以通过向字符串注入变量的方式来构造新的变量,ts4 则可以通过向字符串注入类型的方式来构造新的类型。

type World = "world";

type Greeting = `hello${World}`;

// same as// type Greeting = "hello world";

模版字符串类型可以用于:

1.简化复杂字符串类型的定义

ts4 之后,开发者可以简化对复杂字符串类型的定义,事实上模版字符串类型起到了自动组合类型的效果。

// ts3type Alignment = "top-left" | "top-center" | "top-right" | "middle-left" | "middle-center" | "middle-right"| "bottom-left" | "bottom-center" | "bottom-right"

// ts4type VerticalAlignment = "top" | "middle" | "bottom";

type HorizontalAlignment = "left" | "center" | "right";

type Alignment = `${VerticalAlignment}-${HorizontalAlignment}`

2.修改动态推导的的字符串类型

假设我们想对某个对象的属性变化进行监听并且定义了一个 makeWatchedObject 方法来监听对象属性。

let person = makeWatchedObject({

firstName: "Homer",

age: 42,

location: "Springfield",

});

person.on("firstNameChanged", (newName) => {

console.log(`firstName was changed to${newName}!`);

});

person.on("ageChanged", (newAge) => {

console.log(`age was changed to${newAge}!`);

});

person.on("locationChanged", (newLocation) => {

console.log(`location was changed to${newLocation}!`);

});

属性变化的事件名格式为 ${property}Changed,采用模版字符串类型定义 makeWatchedObject 类型:

type PropEventSource = {

on(eventName: `${string & keyof T}Changed`, callback: (v: any) => void): void;

};

declare function makeWatchedObject(obj: T): T & PropEventSource;

更进一步,我们可以通过模版字符串类型来推导 callback: (v: any) => void 中 v的类型:

type PropEventSource = {

on

(eventName: `${K}Changed`, callback: (v: T[K]) => void): void;

};

declare function makeWatchedObject(obj: T): T & PropEventSource;

映射类型属性重映射

在 ts4 之前的版本中,开发者可通过映射类型从旧类型中创建新类型,如常用 Partial 类型:

type Partial = {

[P in keyof T]?: T[P];

}

interface Props {

name: string

age: number

}

type NewProps = Partial

映射类型最大的作用是将旧类型的每个属性按照相同的方式映射到新类型中,像 Partial 就是把所有属性都映射成可选,但是在 ts4 之前的版本对属性的转换方式仅仅局限在增加属性修饰符(readonly,? 等)上:

type Readonly = {

readonly [P in keyof T]: T[P];

}

type Partial = {

[P in keyof T]?: T[P];

}

从 ts4 开始,将支持对属性更进一步的映射,开发者可以通过 as 保留字重新构造想要的属性。

1.属性重命名

type Getters = {

[K in keyof T as `get${Capitalize}`]: () => T[K]

};

interface Props {

name: string;

age: number;

location: string;

}

type NewProps = Getters;

/* 等于interface NewProps {getName: () => string;getAge: () => number;getLocation: () => string;}*/

2.去除属性

type RemoveField = {

[K in keyof T as Exclude]: T[K]

};

interface Props {

foo: string;

bar: number;

}

type NewProps = RemoveField;

/* 等于type NewProps = {bar: number;};*/

3.过滤属性

type GetMethods = { [P in keyof T as T[P] extends Function ? P : never]: T[P] };

interface Props {

foo(): number,

bar: boolean

}

type NewProps = GetMethods;

/* 等于type NewProps = {foo(): number;};*/

4.衍生属性

type DoubleProps = { [P in keyof T & string as `${P}1` | `${P}2`]: T[P] }

interface Props {

a: string,

b: number

}

type NewProps = DoubleProps;

/* 等于type NewProps = { a1: string, a2: string, b1: number, b2: number }*/

递归条件类型

ts3 支持通过特定条件判断来获取类型:

type IsString = T extends string ? true : false;

type A = IsString; // truetype B = IsString; // false

为了更好的支持类型推断,ts4 在条件类型的基础上又增加了可递归的条件判断,常用递归条件类型模式为:type A = T extends B ? A : T

比如常见的数组拍平函数 deepFlatten,假设其输入为任意嵌套的未知类型数组,对应的输出为推导的某类型数组,通过递归条件类型表达为:

// 可递归条件类型type ElementType =

T extends ReadonlyArray ? ElementType : T;

function deepFlatten(x: T): ElementType[] {

throw "not implemented";

}

// 全部返回 'number[]':deepFlatten([1, 2, 3]);

deepFlatten([[1], [2, 3]]);

deepFlatten([[1], [[2]], [[[3]]]]);

再一个经典的例子便是推断 await 语句的返回值类型:

type Awaited =

T extends PromiseLike ? Awaited : T;

type P1 = Awaited>; // stringtype P2 = Awaited>>; // stringtype P3 = Awaited | undefined>>; // string | number | undefined

值得注意的是,递归条件类型虽然强大,但是会额外增加编译器在检查 ts 类型时的耗时,出于编译性能考虑,ts 编译器会对递归条件类型的层级有所限制,一旦超过了这个限制,在编译时就会报错,开发者在使用递归条件类型时也应该控制好输入的类型层级。

其他新特性新增 --noUncheckedIndexedAccess 编译选项,强制开发者显示校验属性是否存在

paths 可以不依赖 baseUrl 单独配置

支持配置 "jsx": "react-jsx|react-jsxdev" 来指定是否使用 React17 的 jsx 和 jsxs 工厂函数

编译器对 JSDoc @see 标签的支持

不兼容变化abstract 成员不能再被标记为 async

any/unknown 类型在 falsy 表达式中的类型推断方式改变

declare let foo: unknown;

declare let somethingElse: { someProp: string };

let x = foo && somethingElse;

/*ts3 x 类型为 { someProp: string }ts4 x 类型为 unknown*/Promise.resolve 函数参数不再是可选的

spread 运算符的扩展数据类型其对应属性变为可选

interface Person {

name: string;

age: number;

location: string;

}

interface Animal {

name: string;

owner: Person;

}

function copyOwner(pet?: Animal) {

return {

...(pet && pet.owner),

otherStuff: 123

}

}

/*ts3 返回类型为 { x: number } | { x: number, name: string, age: number, location: string }ts4 返回类型为 { x: number; name?: string; age?: number; location?: string;}*/

参考文章Announcing TypeScript 4.1 | TypeScript​devblogs.microsoft.com

ts 修饰符_TS4 新特性一览相关推荐

  1. Java8-19新特性一览 ,认识全新的前沿技术

    文章目录 Java8-19新特性一览 ,认识全新的前沿技术 前言 你的收获 Java发展趋势 准备工作 新特性 1.接口private 1).说明 2).案例 3).注意 2.类型推断 1).说明 2 ...

  2. 深入解析 | Oracle Database 20c 十大新特性一览

    在2020年2月14日,Oracle 正式宣布在 Oracle Cloud 发布 Database 20c 的预览版,同时发布了所有的官方文档. 为了和大家及时分享关于 Oracle 20c 引人瞩目 ...

  3. Java11新特性一览

    Java 11是自Java 8以来的又一个LTS版本,是目前全球使用最多的LTS版本之一.下边我们看一下JAVA11的新特性 字符串API增强 在Java 11中,针对String的操作进一步得到加强 ...

  4. JDK 13 新特性一览

    点击上方"方志朋",选择"设为星标" 回复"666"获取新整理的面试资料 作者:木九天 my.oschina.net/mdxlcj/blog ...

  5. 【机器学习】scikit-learn 1.0 版本重要新特性一览

    1 简介 就在几天前,著名的机器学习框架scikit-learn在pypi上释放了其1.0rc1版本,这里给大家科普一下,版本号中的rc是Release Candidate的简称,代表当前的版本是一个 ...

  6. Oracle Database 20c 十大新特性一览

    从大会的分享和公布的资料中,我们整理了其中重要的新特性,汇聚成10个方向,按照惯例,和大家分享. 历史回顾: Oracle Database 20c 新特性: 1.原生的区块链支持 - Native ...

  7. api es7 删除所有数据_【译】ECMAScript 2016 (ES7) 新特性一览

    本文回答了关于下一版 JavaScript(ECMAScript 2016)的以下几个问题: 谁在设计? 如何设计? 会有什么特性? 本文会持续更新以及时反馈最新进展. 1.谁在设计 ECMAScri ...

  8. ES6、ES7、ES8、ES9、ES10新特性一览

    ES全称ECMAScript,ECMAScript是ECMA制定的标准化脚本语言.目前JavaScript使用的ECMAScript版本为ECMA-417.关于ECMA的最新资讯可以浏览 ECMA n ...

  9. HTML5和CSS3新特性一览

    转自:http://www.cnblogs.com/star91/p/5659134.html HTML5 1.HTML5 新元素 HTML5提供了新的元素来创建更好的页面结构: 标签 描述 < ...

  10. Java7新特性一览

    转自:点击这里 官方:点击这里 Java7于2011年7月发布,相较于java6具备如下新特性: --------------------------------------------------- ...

最新文章

  1. Python自动化运维之5、内置函数
  2. CSS中控制不换行属性
  3. Mybatisplus 自动生成字段 强制覆盖 null或者空字符串也覆盖
  4. 如何实现一个循环显示超长图片的控件
  5. 微信应该砍掉这些功能
  6. 百面机器学习 #3 经典算法:01-1 线性可分(硬间隔)支撑向量机SVM
  7. 一本专门解决网站可用性和易用性问题的实用书籍
  8. mysql+keepalived实现双主自由切换
  9. python进阶(一)关联sql的算法操作
  10. java visibility_浅析Android中的visibility属性
  11. Windows开发——内存读写API
  12. 【语音分析】基于matlab线性预测系数对比【含Matlab源码 557期】
  13. 曾仕强主讲:易经的奥秘(全文讲义)
  14. java判断简体和繁体字_java获取系统语言(区分简体中文和繁体中文)
  15. AE zoom to selected 地图刷新
  16. java中css js是什么_js、jsp、css都是什么意思?
  17. python并行编程 - 介绍篇
  18. Js打开QQ聊天对话窗口
  19. 如何学计算机作文3000到500,作文学习电脑500字(共8篇)
  20. 论表现手法与表达方式

热门文章

  1. 美团商品知识图谱的构建及应用
  2. 金山毒霸推新产品金山卫士 正面狙击奇虎360
  3. 关于 nth-child(n)的几种写法。
  4. opencv Mat指针读取、修改像素值
  5. 数据泵导入报错ORA-39125和LPX-00225
  6. als算法参数_spark ALS算法
  7. layui模板引擎的使用1
  8. 电影视频剪辑怎么做?分享三个小技巧,剪辑其实也不难
  9. 【HTML5】字体删除线代码
  10. Emeditor -- windows最强txt编辑器,没有之一