TypeScript 2.6

严格的函数类型

¥Strict function types

TypeScript 2.6 引入了一个新的严格检查标志 strictFunctionTypesstrictFunctionTypes 开关属于 strict 系列开关,这意味着它在 strict 模式下默认开启。你可以通过在命令行或 tsconfig.json 中设置 --strictFunctionTypes false 来选择退出。

¥TypeScript 2.6 introduces a new strict checking flag, strictFunctionTypes. The strictFunctionTypes switch is part of the strict family of switches, meaning that it defaults to on in strict mode. You can opt-out by setting --strictFunctionTypes false on your command line or in your tsconfig.json.

strictFunctionTypes 下,函数类型参数的位置检查是逆变的,而不是双变的。有关函数类型方差含义的背景信息,请查看 什么是协变和逆变?

¥Under strictFunctionTypes function type parameter positions are checked contravariantly instead of bivariantly. For some background on what variance means for function types check out What are covariance and contravariance?.

更严格的检查适用于所有函数类型,但源自方法或构造函数声明的函数类型除外。方法被排除在外,是为了确保泛型类和接口(例如 Array<T>)继续保持协变关系。

¥The stricter checking applies to all function types, except those originating in method or constructor declarations. Methods are excluded specifically to ensure generic classes and interfaces (such as Array<T>) continue to mostly relate covariantly.

考虑以下示例,其中 AnimalDogCat 的超类型:

¥Consider the following example in which Animal is the supertype of Dog and Cat:

ts
declare let f1: (x: Animal) => void;
declare let f2: (x: Dog) => void;
declare let f3: (x: Cat) => void;
f1 = f2; // Error with --strictFunctionTypes
f2 = f1; // Ok
f2 = f3; // Error

第一个赋值在默认类型检查模式下是允许的,但在严格函数类型模式下会被标记为错误。直观地说,默认模式允许赋值,因为它可能是合理的,而严格函数类型模式会将其视为错误,因为它无法证明是合理的。在这两种模式下,第三次赋值都是错误的,因为它永远不合理。

¥The first assignment is permitted in default type checking mode, but flagged as an error in strict function types mode. Intuitively, the default mode permits the assignment because it is possibly sound, whereas strict function types mode makes it an error because it isn’t provably sound. In either mode the third assignment is an error because it is never sound.

另一种描述该示例的方式是,在默认类型检查模式下,类型 (x: T) => void 对于 T 是双变的(即协变或逆变),但在严格函数类型模式下,对于 T 是逆变的。

¥Another way to describe the example is that the type (x: T) => void is bivariant (i.e. covariant or contravariant) for T in default type checking mode, but contravariant for T in strict function types mode.

示例

¥Example

ts
interface Comparer<T> {
compare: (a: T, b: T) => number;
}
declare let animalComparer: Comparer<Animal>;
declare let dogComparer: Comparer<Dog>;
animalComparer = dogComparer; // Error
dogComparer = animalComparer; // Ok

第一个赋值现在是一个错误。实际上,TComparer<T> 中是逆变的,因为它仅用于函数类型参数位置。

¥The first assignment is now an error. Effectively, T is contravariant in Comparer<T> because it is used only in function type parameter positions.

顺便说一句,虽然某些语言(例如 C# 和 Scala)需要变体注解(out/in+/-),但由于 TypeScript 的结构化类型系统,在泛型类型中实际使用类型参数时,变体会自然产生。

¥By the way, note that whereas some languages (e.g. C# and Scala) require variance annotations (out/in or +/-), variance emerges naturally from the actual use of a type parameter within a generic type due to TypeScript’s structural type system.

注意

¥Note

strictFunctionTypes 下,如果 compare 声明为方法,则仍然允许第一次赋值。实际上,TComparer<T> 中是双变的,因为它仅用于方法参数位置。

¥Under strictFunctionTypes the first assignment is still permitted if compare was declared as a method. Effectively, T is bivariant in Comparer<T> because it is used only in method parameter positions.

ts
interface Comparer<T> {
compare(a: T, b: T): number;
}
declare let animalComparer: Comparer<Animal>;
declare let dogComparer: Comparer<Dog>;
animalComparer = dogComparer; // Ok because of bivariance
dogComparer = animalComparer; // Ok

TypeScript 2.6 还改进了涉及逆变位置的类型推断:

¥TypeScript 2.6 also improves type inference involving contravariant positions:

ts
function combine<T>(...funcs: ((x: T) => void)[]): (x: T) => void {
return x => {
for (const f of funcs) f(x);
};
}
function animalFunc(x: Animal) {}
function dogFunc(x: Dog) {}
let combined = combine(animalFunc, dogFunc); // (x: Dog) => void

以上,所有对 T 的推断都源自逆变位置,因此我们推断出 T 的最佳通用子类型。这与从协变位置推断形成对比,在协变位置推断最佳的公共超类型。

¥Above, all inferences for T originate in contravariant positions, and we therefore infer the best common subtype for T. This contrasts with inferences from covariant positions, where we infer the best common supertype.

在模块中缓存带标签的模板对象

¥Cache tagged template objects in modules

TypeScript 2.6 修复了标记字符串模板的触发问题,使其更好地与 ECMAScript 规范保持一致。根据 ECMAScript 规范,每次评估模板标签时,都应将相同的模板字符串对象(相同的 TemplateStringsArray)作为第一个参数传递。在 TypeScript 2.6 之前,每次生成的输出都是一个全新的模板对象。虽然字符串内容相同,但此问题会影响使用字符串标识进行缓存失效的库,例如 lit-html

¥TypeScript 2.6 fixes the tagged string template emit to align better with the ECMAScript spec. As per the ECMAScript spec, every time a template tag is evaluated, the same template strings object (the same TemplateStringsArray) should be passed as the first argument. Before TypeScript 2.6, the generated output was a completely new template object each time. Though the string contents are the same, this emit affects libraries that use the identity of the string for cache invalidation purposes, e.g. lit-html.

示例

¥Example

ts
export function id(x: TemplateStringsArray) {
return x;
}
export function templateObjectFactory() {
return id`hello world`;
}
let result = templateObjectFactory() === templateObjectFactory(); // true in TS 2.6

生成以下代码:

¥Results in the following generated code:

js
"use strict";
var __makeTemplateObject =
(this && this.__makeTemplateObject) ||
function(cooked, raw) {
if (Object.defineProperty) {
Object.defineProperty(cooked, "raw", { value: raw });
} else {
cooked.raw = raw;
}
return cooked;
};
function id(x) {
return x;
}
var _a;
function templateObjectFactory() {
return id(
_a || (_a = __makeTemplateObject(["hello world"], ["hello world"]))
);
}
var result = templateObjectFactory() === templateObjectFactory();

注意:此更改带来了一个新的 emit 助手 __makeTemplateObject;如果你将 importHelperstslib 一起使用,请更新到 1.8 或更高版本。

¥Note: This change brings a new emit helper, __makeTemplateObject; if you are using importHelpers with tslib, an updated to version 1.8 or later.

命令行上的本地化诊断

¥Localized diagnostics on the command line

TypeScript 2.6 npm 软件包附带了 13 种语言的本地化诊断消息版本。在命令行上使用 --locale 标志时,本地化消息可用。

¥TypeScript 2.6 npm package ships with localized versions of diagnostic messages for 13 languages. The localized messages are available when using the --locale flag on the command line.

示例

¥Example

俄语错误信息:

¥Error messages in Russian:

sh
c:\ts>tsc --v
Version 2.6.0-dev.20171003
c:\ts>tsc --locale ru --pretty c:\test\a.ts
../test/a.ts(1,5): error TS2322: Тип ""string"" не может быть назначен для типа "number".
1 var x: number = "string";
~

日语帮助:

¥And help in Japanese:

sh
PS C:\ts> tsc --v
Version 2.6.0-dev.20171003
PS C:\ts> tsc --locale ja-jp
バージョン 2.6.0-dev.20171003
構文: tsc [オプション] [ファイル ...]
例: tsc hello.ts
tsc --outFile file.js file.ts
tsc @args.txt
オプション:
-h, --help このメッセージを表示します。
--all コンパイラ オプションをすべて表示します。
-v, --version コンパイラのバージョンを表示します。
--init TypeScript プロジェクトを初期化して、tsconfig.json ファイルを作成します。
-p ファイルまたはディレクトリ, --project ファイルまたはディレクトリ 構成ファイルか、'tsconfig.json' を含むフォルダーにパスが指定されたプロジェクトをコ
ンパイルします。
--pretty 色とコンテキストを使用してエラーとメッセージにスタイルを適用します (試験的)。
-w, --watch 入力ファイルを監視します。
-t バージョン, --target バージョン ECMAScript のターゲット バージョンを指定します: 'ES3' (既定)、'ES5''ES2015''ES2016''ES2017''ES
NEXT'
-m 種類, --module 種類 モジュール コード生成を指定します: 'none''commonjs''amd''system''umd''es2015''ESNext'
--lib コンパイルに含めるライブラリ ファイルを指定します:
'es5' 'es6' 'es2015' 'es7' 'es2016' 'es2017' 'esnext' 'dom' 'dom.iterable' 'webworker' 'scripthost' 'es201
5.core' 'es2015.collection' 'es2015.generator' 'es2015.iterable' 'es2015.promise' 'es2015.proxy' 'es2015.reflect' 'es2015.symbol' 'es2015.symbol.wellkno
wn' 'es2016.array.include' 'es2017.object' 'es2017.sharedmemory' 'es2017.string' 'es2017.intl' 'esnext.asynciterable'
--allowJs javascript ファイルのコンパイルを許可します。
--jsx 種類 JSX コード生成を指定します: 'preserve''react-native''react'
-d, --declaration 対応する '.d.ts' ファイルを生成します。
--sourceMap 対応する '.map' ファイルを生成します。
--outFile ファイル 出力を連結して 1 つのファイルを生成します。
--outDir ディレクトリ ディレクトリへ出力構造をリダイレクトします。
--removeComments コメントを出力しないでください。
--noEmit 出力しないでください。
--strict strict 型チェックのオプションをすべて有効にします。
--noImplicitAny 暗黙的な 'any' 型を含む式と宣言に関するエラーを発生させます。
--strictNullChecks 厳格な null チェックを有効にします。
--noImplicitThis 暗黙的な 'any' 型を持つ 'this' 式でエラーが発生します。
--alwaysStrict 厳格モードで解析してソース ファイルごとに "use strict" を生成します。
--noUnusedLocals 使用されていないローカルに関するエラーを報告します。
--noUnusedParameters 使用されていないパラメーターに関するエラーを報告します。
--noImplicitReturns 関数の一部のコード パスが値を返さない場合にエラーを報告します。
--noFallthroughCasesInSwitch switch ステートメントに case のフォールスルーがある場合にエラーを報告します。
--types コンパイルに含む型宣言ファイル。
@<ファイル>

使用 ’// @ts-ignore’ 注释抑制 .ts 文件中的错误

¥Suppress errors in .ts files using ’// @ts-ignore’ comments

TypeScript 2.6 支持使用位于错误行上方的 // @ts-ignore 注释来抑制 .ts 文件中的错误。

¥TypeScript 2.6 supports suppressing errors in .ts files using // @ts-ignore comments placed above the offending lines.

示例

¥Example

ts
if (false) {
// @ts-ignore: Unreachable code error
console.log("hello");
}

// @ts-ignore 注释会抑制源自下一行的所有错误。建议在 @ts-ignore 之后的注释中解释要抑制哪个错误。

¥A // @ts-ignore comment suppresses all errors that originate on the following line. It is recommended practice to have the remainder of the comment following @ts-ignore explain which error is being suppressed.

请注意,此注释仅用于抑制错误报告,我们建议你谨慎使用此注释。

¥Please note that this comment only suppresses the error reporting, and we recommend you use this comments very sparingly.

更快的 tsc --watch

¥Faster tsc --watch

TypeScript 2.6 带来了更快的 --watch 实现。新版本优化了使用 ES 模块的代码生成和代码库检查。在模块文件中检测到的更改将只导致重新生成更改的模块及其依赖的文件,而不是整个项目。拥有大量文件的项目应该从此更改中获得最大收益。

¥TypeScript 2.6 brings a faster --watch implementation. The new version optimizes code generation and checking for code bases using ES modules. Changes detected in a module file will result in only regenerating the changed module, and files that depend on it, instead of the whole project. Projects with a large number of files should reap the most benefit from this change.

新的实现还提升了 tsserver 中监听的性能。监视器逻辑已被完全重写,以便更快地响应更改事件。

¥The new implementation also brings performance enhancements to watching in tsserver. The watcher logic has been completely rewritten to respond faster to change events.

只写引用现在标记为未使用

¥Write-only references now flagged as unused

TypeScript 2.6 修订了 noUnusedLocalsnoUnusedParameters 编译器选项 的实现。只写入但从不读取的声明现在被标记为未使用。

¥TypeScript 2.6 adds revised implementation the noUnusedLocals and noUnusedParameters compiler options. Declarations are only written to but never read from are now flagged as unused.

示例

¥Example

下面的 nm 都将被标记为未使用,因为它们的值永远不会被读取。以前,TypeScript 只会检查它们的值是否被引用。

¥Below both n and m will be marked as unused, because their values are never read. Previously TypeScript would only check whether their values were referenced.

ts
function f(n: number) {
n = 0;
}
class C {
private m: number;
constructor() {
this.m = 0;
}
}

此外,仅在自身函数体内部调用的函数会被视为未使用的。

¥Also functions that are only called within their own bodies are considered unused.

示例

¥Example

ts
function f() {
f(); // Error: 'f' is declared but its value is never read
}