- TypeScript 4.2">TypeScript 4.2
- Smarter Type Alias Preservation">Smarter Type Alias Preservation
- Leading/Middle Rest Elements in Tuple Types">Leading/Middle Rest Elements in Tuple Types
- Stricter Checks For The
inOperator">Stricter Checks For TheinOperator [--noPropertyAccessFromIndexSignature](https://devblogs.microsoft.com/typescript/announcing-typescript-4-2/#no-property-access-index-signature)abstractConstruct Signatures">abstractConstruct Signatures- The
--explainFilesFlag">The--explainFilesFlag - Improved Uncalled Function Checks in Logical Expressions">Improved Uncalled Function Checks in Logical Expressions
- Destructured Variables Can Be Explicitly Marked as Unused">Destructured Variables Can Be Explicitly Marked as Unused
- Relaxed Rules Between Optional Properties and String Index Signatures">Relaxed Rules Between Optional Properties and String Index Signatures
- Declare Missing Helper Function">Declare Missing Helper Function
- Breaking Changes">Breaking Changes
- TypeScript 4.1
- Typescript 4.0">Typescript 4.0
- Variadic Tuple Types
- Labeled Tuple Elements
- 2.4.3 Class Property Inference from Constructors
- 2.4.4 Short-Circuiting Assigment Operators
- 2.4.5
unknownoncatchClause Bindings - 2.4.6 Custom JSX Factories
- 2.4.7 Speed Improvements in build mode witch
--noEmitOnError - 2.4.8
--incrementalwith--noEmit - 2.4.9 Editor Improvements
- 2.4.10 Our New Website!
- 2.4.11 Breaking Changes
- ‘foo’ is defined as an accessor in class ‘Base’, but is overridden here in ‘Derived’ as an instance property.
- The operand of a ‘delete’ operator must be optional.
- 2.2.2 ECMAScript Private Fields
- console.log(instance.cHelper()); // prints ‘20’
- console.log(instance.dHelper()); // prints ‘20’
- console.log(new C().foo); // prints ‘10’
- console.log(new C()[“foo”]); // prints ‘10’
- 2.2.3
export * as nsSyntax - 2.2.4 Top-Level
await - 2.2.5
es2020作为target和module的选项 - 2.2.5 JSDoc Property Modifiers
- 2.2.6 Better Directory Watching on Linux and
watchOptions - 2.2.7 “Fast and Loose” Incremental Checking
- Typescript 3.7
- Optional Chaining
?.- 3 Assertion Functions
- 4 Better Support for
never- Returning Functions - 5 (More) Recursive Type Aliases
- 6
--declarationand--allowJs - 7 The
useDefineForClassFields - 8 Build-Free Editing with Project References
- 9 Uncalled Function Checks
- 2.1.10 ts-nocheck in TypeScript Files
- 2.1.11 Semicolon Formatter Option
- 2.1.12 Breaking Changes
- Optional Chaining
TypeScript 4.2
Smarter Type Alias Preservation
TypeScript通过类型别名(type alias)来给类型声明新的名字。如果你正在编写一系列的函数,都使用了 string | number | boolean 类型,那么可以声明一个类型别名来避免重复。
type BasicPrimitive = string | number | boolean;
当重用类型别名时,TypeScript已经使用了一组规则和推测来显示类型。例如以下代码片断:
export type BasicPrimitive = number | string | boolean;export function doStuff(value: BasicPrimitive) {let x = value;return x;}
当使用Visual Studio、Visual Studio Code或者是TypeScript Playground编辑器开发时,如果鼠标悬停在 x 上,可以看到一个快捷信息栏中显示类型 BasicPrimitive。同样地,如果生成该文件的类型声明文件(输出 .d.ts 文件),其中 doStuff 函数会返回 BasicPrimitive 类型。
但是,如果返回一个 BasicPrimitive 或 undefined,会发生什么呢?
export type BasicPrimitive = number | string | boolean;export function doStuff(value: BasicPrimitive) {if (Math.random() < 0.5) {return undefined;}return value;}
我们可以看看在TypeScript playground中会发生什么。TypeScript不会如我们期望的那样显示 doStuff 的返回类型为 BasicPrimitive | undefined,而是显示 string | number | boolean | undefined!为什么会这样?
这涉及到TypeScrpt在内部是如何表示类型的。当通过一个或多个联合类型(union type)来创建一个新的联合类型时,TypeScript将规范化(normalize)这些类型成一个新的、扁平化的联合类型,从而导致丢失了类型信息。类型检查器将会从 string | number | boolean | undefined 来查找每一个类型组合来查看哪些类型别名可能被使用了,甚至可能存在多个 string | number | boolean 的类型别名。
在TypeScript 4.2,内部实现将更加智能一些。通过始终保存类型编写和创建的信息来追踪类型如何创建的。也追踪和区分了类型别名和这些别名的实例(instances)。
能够按照TypeScript用户编写代码时的意图来实现类型,可以避免某些超长显示的类型,从而使得生成的 d.ts 文件、错误信息以及编辑器中的类型显示可读性更好。这使得TypeScript对初学者来说更加友好。
具体细节可以参考:
the first pull request that improves various cases around preserving union type aliases
a second pull request that preserves indirect aliases.
Leading/Middle Rest Elements in Tuple Types
在TypeScript中,元组类型(tuple types)是一个有指定长度和元素类型的模型数组。
// A tuple that stores a pair of numberslet a: [number, number] = [1, 2];// A tuple that stores a string, a number, and a booleanlet b: [string, number, boolean] = ["hello", 42, true];
随着时间的推移,TypeScript的元组类型已经变得越来越复杂,因为他们也被用来模型化JavaScript,例如参数列表(parameter lists)。结果,可选元素类型(optional element),可变长元素类型(rest elements)以及用来改进工具性和可读性的类型标签(labels)也被引入。
// A tuple that has either one or two strings.let c: [string, string?] = ["hello"];c = ["hello", "world"];// A labeled tuple that has either one or two strings.let d: [first: string, second?: string] = ["hello"];d = ["hello", "world"];// A tuple with a *rest element* - holds at least 2 strings at the front,// and any number of booleans at the back.let e: [string, string, ...boolean[]];e = ["hello", "world"];e = ["hello", "world", false];e = ["hello", "world", true, false, true];
在TypeScript 4.2中,可变长元素类型的使用得到的扩展。在之前的版本中,TypeScript只允许 ...rest 元素出现在元组类型的最后位置。
而现在,可变长元素类型可以出现在元组类型的任何位置,只需要遵循少量的限制。
let foo: [...string[], number];foo = [123];foo = ["hello", 123];foo = ["hello!", "hello!", "hello!", 123];let bar: [boolean, ...string[], boolean];bar = [true, false];bar = [true, "some text", false];bar = [true, "some", "separated", "text", false];
唯一的限制是可变长元素类型可以出现在元组类型的任意位置,但是它的后面不可以再出现可选元素类型或者可变长元素类型。换句话说,每个元组只可以有一个可变长元素类型,并且可变长元素类型后面不可以再有可选元素类型。
interface Clown { /*...*/ }interface Joker { /*...*/ }let StealersWheel: [...Clown[], "me", ...Joker[]];// ~~~~~~~~~~ Error!// A rest element cannot follow another rest element.let StringsAndMaybeBoolean: [...string[], boolean?];// ~~~~~~~~ Error!// An optional element cannot follow a rest element.
这些不是放在结尾处的可变长元素类型可以用来模型化接受任意数量头部参数再紧接着固定数量参数结尾的函数。
declare function doStuff(...args: [...names: string[], shouldCapitalize: boolean]): void;doStuff(/*shouldCapitalize:*/ false)doStuff("fee", "fi", "fo", "fum", /*shouldCapitalize:*/ true);
即使JavaScript没有定义任何语法来模型化头部可变长参数,我们仍然可以声明 doStuff 函数,通过声明 ...args 作为可变长参数,其类型为一个头部使用了可变长元素类型的元组,使得该函数可以接受头部参数。这有助于模型化大量已存在的JavaScript函数!
具体细节,参考原始的pull request.
Stricter Checks For The in Operator
[--noPropertyAccessFromIndexSignature](https://devblogs.microsoft.com/typescript/announcing-typescript-4-2/#no-property-access-index-signature)
abstract Construct Signatures
The --explainFiles Flag
Improved Uncalled Function Checks in Logical Expressions
Destructured Variables Can Be Explicitly Marked as Unused
Relaxed Rules Between Optional Properties and String Index Signatures
Declare Missing Helper Function
Breaking Changes
TypeScript 4.1
1 Recursive Conditional Types
2 undefined in index signatures
3 --noImplicitOverride
Typescript 4.0
Variadic Tuple Types
解决“death by a thousand overloads”问题:
例如concat类型声明:
function concat(arr1: [], arr2: []): [];function concat<A>(arr1: [A], arr2: []): [A];function concat<A, B>(arr1: [A, B], arr2: []): [A, B];function concat<A, B, C>(arr1: [A, B, C], arr2: []): [A, B, C];function concat<A, B, C, D>(arr1: [A, B, C, D], arr2: []): [A, B, C, D];function concat<A, B, C, D, E>(arr1: [A, B, C, D, E], arr2: []): [A, B, C, D, E];function concat<A, B, C, D, E, F>(arr1: [A, B, C, D, E, F], arr2: []): [A, B, C, D, E, F];)function concat<A2>(arr1: [], arr2: [A2]): [A2];function concat<A1, A2>(arr1: [A1], arr2: [A2]): [A1, A2];function concat<A1, B1, A2>(arr1: [A1, B1], arr2: [A2]): [A1, B1, A2];function concat<A1, B1, C1, A2>(arr1: [A1, B1, C1], arr2: [A2]): [A1, B1, C1, A2];function concat<A1, B1, C1, D1, A2>(arr1: [A1, B1, C1, D1], arr2: [A2]): [A1, B1, C1, D1, A2];function concat<A1, B1, C1, D1, E1, A2>(arr1: [A1, B1, C1, D1, E1], arr2: [A2]): [A1, B1, C1, D1, E1, A2];function concat<A1, B1, C1, D1, E1, F1, A2>(arr1: [A1, B1, C1, D1, E1, F1], arr2: [A2]): [A1, B1, C1, D1, E1, F1, A2];// ...
tuple类型的spread可以泛型化
function tail<T extends any[]>(arr: readonly [any, ...T]) {const [_ignored, ...rest] = arr;return rest;}
rest元素可以出现在tuple的任意位置 ```typescript type Strings = [string, string]; type Numbers = [number, number];
type StrStrNumNumBool = […Strings, …Numbers, boolean]; // ^ = type StrStrNumNumBool = [string, string, number, number, boolean]
之前版本的TypeScript会报错:> A rest element must be last in a tuple type.注意,spread的类型长度未知,导出的类型也是未知长度,且后续的类型会被合并进rest元素的类型```typescripttype Strings = [string, string];type Numbers = number[];type Unbounded = [...Strings, ...Numbers, boolean];// ^ = type Unbounded = [string, string, ...(number | boolean)[]]
现在可以为concat重新声明完美类型化的方法签名:
type Arr = readonly any[];function concat<T extends Arr, U extends Arr>(arr1: T, arr2: U): [...T, ...U] {return [...arr1, ...arr2];}
更复杂的场景:
function partialCall(f, ...headArgs) {return (...tailArgs) => f(...headArgs, ...tailArgs);}
type Arr = readonly unknown[];function partialCall<T extends Arr, U extends Arr, R>(f: (...args: [...T, ...U]) => R,...headArgs: T) {return (...tailArgs: U) => f(...headArgs, ...tailArgs);}
使用时:
const foo = (x: string, y: number, z: boolean) => {};const f1 = partialCall(foo, 100);# Argument of type 'number' is not assignable to parameter of type 'string'.const f2 = partialCall(foo, "hello", 100, true, "oops");# Expected 4 arguments, but got 5.// This works!const f3 = partialCall(foo, "hello");// ^ = const f3: (y: number, z: boolean) => void// What can we do with f3 now?// Works!f3(123, true);f3();# Expected 2 arguments, but got 0.f3(123, "hello");# Argument of type 'string' is not assignable to parameter of type 'boolean'.
Labeled Tuple Elements
type Range = [start: number, end: number];type Foo = [first: number, second?: string, ...rest: any[]];type Bar = [first: string, number];# Tuple members must all have names or all not have names.
仅用于文档和开发工具,如编辑器支持,显示重载签名时提高可读性:
2.4.3 Class Property Inference from Constructors
启用noImplicitAny时,TS 4.0可以利用控制流分析(control flow analysis)来确定class的属性类型:
class Square {// Previously both of these were anyarea;// ^ = (property) Square.area: numbersideLength;// ^ = (property) Square.sideLength: numberconstructor(sideLength: number) {this.sideLength = sideLength;this.area = sideLength ** 2;}}
class Square {sideLength;// ^ = (property) Square.sideLength: number | undefinedconstructor(sideLength: number) {if (Math.random()) {this.sideLength = sideLength;}}get area() {return this.sideLength ** 2;# Object is possibly 'undefined'.}}
启用strictPropertyInitialization时,即使使用了确定赋值断言(definite assignment assertion (!)),依然需要显示的类型注释:
class Square {// definite assignment assertion// vsideLength!: number;// type annotationconstructor(sideLength: number) {this.initialize(sideLength);}initialize(sideLength: number) {this.sideLength = sideLength;}get area() {return this.sideLength ** 2;}}
2.4.4 Short-Circuiting Assigment Operators
logical and (&&), logical or (||), and nullish coalescing (??)
if (!a) {a = b;}// ora || (a = b);// aftera ||= b;
let values: string[];(values ?? (values = [])).push("hello");// After(values ??= []).push("hello");
2.4.5 unknown on catch Clause Bindings
之前版本,catch 语句捕获的异常类型总是被设定为any,这意味可以对异常值做任何操作
try {// Do some work} catch (x) {// x has type 'any' - have fun!console.log(x.message);console.log(x.toUpperCase());x++;x.yadda.yadda.yadda();}
4.0可以指定为unknows,此时需要进行类型检查才能操作异常值
try {// ...} catch (e: unknown) {// Can't access values on unknownsconsole.log(e.toUpperCase());# Object is of type 'unknown'.if (typeof e === "string") {// We've narrowed 'e' down to the type 'string'.console.log(e.toUpperCase());}}
- 默认
catch变量的类型没有变更,未来会考虑引入一个新的模式flag--strict。 - 目前可以使用lint规则来强制要求
catch变量必须显示地标注类型为:any或者:unknown2.4.6 Custom JSX Factories
在tsconfig.json中可以指定转换JSX时,使用的工厂方法:
```jsx // Note: these pragma comments need to be written // with a JSDoc-style multiline syntax to take effect.{compilerOptions: {target: "esnext",module: "commonjs",jsx: "react",jsxFactory: "h",jsxFragmentFactory: "Fragment",},}
/ @jsx h */ / @jsxFrag Fragment */
import { h, Fragment } from “preact”;
export const Header = ( <>
Welcome
</> );
```javascript// Note: these pragma comments need to be written// with a JSDoc-style multiline syntax to take effect./** @jsx h *//** @jsxFrag Fragment */import { h, Fragment } from "preact";export const Header = (h(Fragment, null,h("h1", null, "Welcome")));
2.4.7 Speed Improvements in build mode witch --noEmitOnError
2.4.8 --incremental with --noEmit
现在可以同时使用--noEmit和--incremental flag来加快构建。
2.4.9 Editor Improvements
Convert to Optional Chaining
/** @deprecated */ Support
Partial Semantic Mode at Startup
启用Partial Semantic模式,通过延缓一些语法分析来加快打开代码文件的速度。
https://devblogs.microsoft.com/typescript/wp-content/uploads/sites/11/2020/08/partialModeFast.mp4
Smarter Auto-Imports
通过package.json中的peerDependencies中列明的包来改进自动importtypescript.preferences.includePackageJsonAutoImports
2.4.10 Our New Website!
全新的TypeScript网站 The TypeScript website
2.4.11 Breaking Changes
lib.d.ts Changes
- types of DOM
document.origin=>self.originProperties Overriding Accessors (and vice versa) is an Error
之前只有使用了useDefineForClassFields设置时,父类子类的Accessor和Property相互重写(overriding)才会报错,现在4.0版本无论是否配置都会报错。 ```typescript class Base { get foo() { return 100; } set foo(value) { // … } }
class Derived extends Base { foo = 10;
‘foo’ is defined as an accessor in class ‘Base’, but is overridden here in ‘Derived’ as an instance property.
}
```typescriptclass Base {prop = 10;}class Derived extends Base {get prop() {# 'prop' is defined as a property in class 'Base', but is overridden here in 'Derived' as an accessor.return 100;}}Try
Operands for delete must be optional
strictNullChecksany,unknown,never,or be optional(containsundefined) ```typescript interface Thing { prop: string; }
function f(x: Thing) { delete x.prop;
The operand of a ‘delete’ operator must be optional.
}
<a name="VnpmR"></a>#### Usage of TypeScript’s Node Factory is Deprecated4.0提供了一个新的AST Node工厂API,旧版本的工厂函数都被deprecate<a name="tVIp0"></a># TypeScript 3.8<a name="QsJtq"></a>## Type-Only Imports and Exports<a name="qIHkg"></a>##### 代码```typescriptimport type { SomeThing } from "./some-module.js";export type { SomeThing };
说明
- import/export type在运行时会被擦除,也就是说import和export语句不会出现在tsc编译后的代码中
- class在运行时(runtime)是一个值,而在编译时(compile-time)是一个类型,使用上有上下文不同
import type { Component }, { Component as RComponent } from "react";interface ButtonProps {// ...}class Button extends Component<ButtonProps> {// ~~~~~~~~~// error! 'Component' only refers to a type, but is being used as a value here.# // replace with RComponent// ...}
- Compiler flag
importsNotUsedValuesremove抛弃imports,将成为defaultpreserve保留imports,同样会保留imports导致的副作用(side-effects)error保留imports,但有value import只当成类型使用时,报错!目的:防止意外的imports,有副作用的import会被显式引入
2.2.2 ECMAScript Private Fields
代码
class Person {#name: stringconstructor(name: string) {this.#name = name;}greet() {console.log(`Hello, my name is ${this.#name}!`);}}let jeremy = new Person("Jeremy Bearimy");jeremy.#name// ~~~~~// Property '#name' is not accessible outside class 'Person'// because it has a private identifier.
说明
# private fields和private modifier的差别:
- private field使用
#开头,有时候被称为private names 在包含他的class中,private field名称被唯一限定(scoped) ```typescript class C { foo = 10;
cHelper() {
return this.foo;
} }
class D extends C { foo = 20;
dHelper() {return this.foo;}
}
let instance = new D(); // ‘this.foo’ refers to the same property on each instance.
console.log(instance.cHelper()); // prints ‘20’
console.log(instance.dHelper()); // prints ‘20’
```typescriptclass C {#foo = 10;cHelper() {return this.#foo;}}class D extends C {#foo = 20;dHelper() {return this.#foo;}}let instance = new D();// 'this.#foo' refers to a different field within each class.# console.log(instance.cHelper()); // prints '10'# console.log(instance.dHelper()); // prints '20'
private和public不可以用于#private field- 在包含他的class外,private fields不可以被访问或者探知
privatemodifier是编译时的私有性检查, 会被完全擦除,运行时无效;private field是在class外是完全不可访问的,是运行时的私有性检查 ```typescript class C { private foo = 10; }
// This is an error at compile time, // but when TypeScript outputs .js files, // it’ll run fine and print ‘10’.
console.log(new C().foo); // prints ‘10’
// ~~~ // error! Property ‘foo’ is private and only accessible within class ‘C’.
// TypeScript allows this at compile-time // as a “work-around” to avoid the error.
console.log(new C()[“foo”]); // prints ‘10’
```typescriptclass C {#foo = 10;}# console.log(new C().#foo); // SyntaxError// ~~~~// TypeScript reports an error *and*// this won't work at runtime!# console.log(new C()["#foo"]); // prints undefined// ~~~~~~~~~~~~~~~// TypeScript reports an error under 'noImplicitAny',// and this prints 'undefined'.
- TypeScript只在ES6及更高的ECMScript Target支持
#private field,因为底层实现依赖WeakMap来保证私有性;而privatemodifier可以用于所有的Target,甚至ES3。 - 运行速度:
#private field在底层实现中使用了WeakMap会影响性能,虽然一些Runtime可能会对#private field的实现进行优化,比如加速优化过的WeakMap,但并不是在所有Runtime中都会如此。示例
- private field访问导
TypeError
class Square {#sideLength: number;constructor(sideLength: number) {this.#sideLength = sideLength;}equals(other: any) {return this.#sideLength === other.#sideLength;}}const a = new Square(100);const b = { sideLength: 100 };// Boom!// TypeError: attempted to get private field on non-instance// This fails because 'b' is not an instance of 'Square'.console.log(a.equals(b));
- 使用前声明,否则导致
SyntaxError
class C {// No declaration for '#foo'// :(constructor(foo: number) {// SyntaxError!// '#foo' needs to be declared before writing to it.this.#foo = foo;}}
class C {/** @type {number} */#foo;constructor(foo: number) {// This works.this.#foo = foo;}}
2.2.3 export * as ns Syntax
该语法用于export imports的场景,对应特性在ES2020 Target。
目前的代码:
import * as utilities from "./utilities.js";export { utilities };
TS 3.8版本:
export * as utilities from "./utilities.js";
2.2.4 Top-Level await
解决await只能用函数体的问题:
- 只能使用在module中,可以用
export {}来保证 - 只能使用在
target>=es2017,且module设置为esnext或system - TS 3.8开始支持
ES2020作为module和target选项
目前的代码:
async function main() {const response = await fetch("...");const greeting = await response.text();console.log(greeting);}main().catch(e => console.error(e))
TS 3.8版本:
2.2.5 es2020作为target和module的选项
支持ECMAScript 2020的特性
TS 3.8通过
allowJs支持JavaScript源文件- 通过设置
checkJS或使用//注释,也支持对这些文件进行类型检查 支持利用JSDoc来进行类型检查
- @private
- @public
- @protected
- @readonly ,
2.2.6 Better Directory Watching on Linux and
引入watchOptionswatchOptions来更好的配置文件监视(watch)策略,详细配置如下:
watchFile设置单个文件的监视策略,可选值如下:fixedPollingInterval一秒钟内按固定的时间间隔来检查每个文件priorityPollingInterval一秒钟内检查每个文件数次,但使用启发式策略来降低某些类型文件的检查频率dynamicPriorityPolling使用一个动态队列,修改频率越低的文件检查频率越低useFsEvents(默认值) 尝试使用操作系统或文件系统原生事件来监视文件变更useFsEventsOnParentDirectory尝试使用操作系统或文件系统原生事件来监听父文件夹的变更,该选项可以降低文件watcher的数量,但代价是牺牲精确度。
watchDirectory设置当系统缺乏递归式文件监视功能时整个目录树的监视策略。 可选值如下:fixedPollingInterval一秒钟内按固定的时间间隔来检查每个文件dynamicPriorityPolling一秒钟内检查每个文件数次,但使用启发式策略来降低某些类型文件的检查频率useFsEvents(默认值) 尝试使用操作系统原生事件来监视文件变更
fallbackPolling: 当使用文件系统事件是,该选项用来指定系统已经耗尽或者不支持原生文件watcher时的轮询策略fixedPollingIntervalpriorityPollingIntervaldynamicPriorityPolling
synchronousWatchDirectory关闭文件夹的延时监控。
{// Some typical compiler options"compilerOptions": {"target": "es2020","moduleResolution": "node",// ...},// NEW: Options for file/directory watching"watchOptions": {// Use native file system events for files and directories"watchFile": "useFsEvents","watchDirectory": "useFsEvents",// Poll files for updates more frequently// when they're updated a lot."fallbackPolling": "dynamicPriority"}}
2.2.7 “Fast and Loose” Incremental Checking
compiler选项: assumeChangesOnlyAffectDirectDependencies
fileA.ts <- fileB.ts <- fileC.ts <- fileD.ts
--watch模式下,fileA变化将导致fileB,fileC,fileD都被重新进行检查启用
assumeChangesOnlyAffectDirectDependencies,只用fileA和fileB被重新检查Typescript 3.7
Optional Chaining
?.检查变量是否是
nullundefinedlet x = foo?.bar.baz();
let x = (foo === null || foo === undefined) ?undefined :foo.bar.baz();
- But if
foo.barisnullorundefined….. &&vs?.:'',0,NaN,false```typescript // Before if (foo && foo.bar && foo.bar.baz) { // … }
// After-ish if (foo?.bar?.baz) { // … }
<a name="Ih2jb"></a>### 2 Nullish Coalescing `??````typescriptlet x = foo ?? bar();
let x = (foo !== null && foo !== undefined) ?foo :bar();
3 Assertion Functions
function yell(str) {assert(typeof str === "string");return str.toUppercase();// ~~~~~~~~~~~// error: Property 'toUppercase' does not exist on type 'string'.// Did you mean 'toUpperCase'?}
asserts condition
function assert(condition: any, msg?: string): asserts condition {if (!condition) {throw new AssertionError(msg)}}
- asserts type
function assertIsString(val: any): asserts val is string {if (typeof val !== "string") {throw new AssertionError("Not a string!");}}
- Similar to type predicate signatures
4 Better Support for
never- Returning Functions5 (More) Recursive Type Aliases
6
--declarationand--allowJs7 The
useDefineForClassFields8 Build-Free Editing with Project References
9 Uncalled Function Checks
2.1.10 ts-nocheck in TypeScript Files
2.1.11 Semicolon Formatter Option
2.1.12 Breaking Changes
2.1.12.1 DOM Changes
2.1.12.2 Function Truthy Checks
2.1.12.3 Local and Imported Type Declarations Now Conflict
2.1.12.4 API Changes
2.3 TypeScript 3.9
2.3.1 改进Promise相关的类型推导和Promise.all
TypeScript 3.7版本更新了Promise.all和Promise.race等函数的声明,但是带来了一些问题,特别是当类型值混合了null和unefined时。
interface Lion {roar(): void}interface Seal {singKissFromARose(): void}async function visitZoo(lionExhibit: Promise<Lion>, sealExhibit: Promise<Seal | undefined>) {let [lion, seal] = await Promise.all([lionExhibit, sealExhibit]);lion.roar(); // uh oh// ~~~~// Object is possibly 'undefined'.}
interface PromiseConstructor {readonly prototype: Promise<any>;new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): Promise<T>;all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>;all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>;all<T1, T2, T3, T4, T5, T6, T7, T8>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): Promise<[T1, T2, T3, T4, T5, T6, T7, T8]>;all<T1, T2, T3, T4, T5, T6, T7>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): Promise<[T1, T2, T3, T4, T5, T6, T7]>;all<T1, T2, T3, T4, T5, T6>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): Promise<[T1, T2, T3, T4, T5, T6]>;all<T1, T2, T3, T4, T5>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>, T5 | PromiseLike<T5>]): Promise<[T1, T2, T3, T4, T5]>;all<T1, T2, T3, T4>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike<T4>]): Promise<[T1, T2, T3, T4]>;all<T1, T2, T3>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): Promise<[T1, T2, T3]>;all<T1, T2>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): Promise<[T1, T2]>;all<T>(values: readonly (T | PromiseLike<T>)[]): Promise<T[]>;// see: lib.es2015.iterable.d.ts// all<T>(values: Iterable<T | PromiseLike<T>>): Promise<T[]>;race<T>(values: readonly T[]): Promise<T extends PromiseLike<infer U> ? U : T>;// see: lib.es2015.iterable.d.ts// race<T>(values: Iterable<T>): Promise<T extends PromiseLike<infer U> ? U : T>;reject<T = never>(reason?: any): Promise<T>;resolve<T>(value: T | PromiseLike<T>): Promise<T>;resolve(): Promise<void>;}declare var Promise: PromiseConstructor;
2.3.2 awaited Type
被移出3.9版本
2.3.3 Speed Improvements
- unions
- intersections
- conditional types
- mapped types
2.3.4 // @ts-expect-error Comment
压制TypeScript报错
