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();

注意:此更改引入了一个新的触发辅助工具 __makeTemplateObject; 如果你正在将 importHelperstslib 一起使用,请更新到版本 1.8 或更高版本。

命令行上的本地化诊断

🌐 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 文件中使用 ’// @ts-ignore’ 注释来抑制错误

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

TypeScript 2.6 支持在 .ts 文件中使用放在有问题代码行上方的 // @ts-ignore 注释来抑制错误。

🌐 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
}