TypeScript 2.6.1 変更点


訂正1: コメントで指摘があった Contravariant→反変では？ を反映。[co](https://ejje.weblio.jp/content/co)と[contra](https://ejje.weblio.jp/content/contra)…

こんにちは[ソウゾウ社](https://www.souzoh.com/jp/)に転職しました[@vvakame](https://twitter.com/vvakame)です。
今回は結構気持ちよくなる更新が多いです。

[TypeScript 2.6.1](https://blogs.msdn.microsoft.com/typescript/2017/10/31/announcing-typescript-2-6/)がアナウンスされました。

[What's new in TypeScriptも更新](https://github.com/Microsoft/TypeScript/wiki/What's-new-in-TypeScript#typescript-26)されているようです。
[破壊的変更](https://github.com/Microsoft/TypeScript/wiki/Breaking-Changes#typescript-26)もあるよ！

## 変更点まとめ

* 関数の引数の型についてのチェックを強化 [Strict function types](https://github.com/Microsoft/TypeScript/pull/18654)
	* `(d: Dog) => void` 的な関数を `(a: Animal) => void` 的な変数に突っ込めてたのを弾けるようになった
* タグ付きテンプレートリテラルがキャッシュされるようになった [Cached tagged template objects in modules](https://github.com/Microsoft/TypeScript/pull/18300)
	* よりECMAScriptの仕様に準拠した形
	* 関数の第一引数に渡される `TemplateStringsArray` は複数回実行した時、前回オブジェクトと `===` で比較した時trueになるのが正しかった
* エラーメッセージの各国語ローカライズがnpmにもshipされるようになった [Include localized diagnostics in npm](https://github.com/Microsoft/TypeScript/pull/18702)
	* `--local ja` 的な
	* 結構前からあってVisualStudioバンドルのやつとかは日本語化されてた(はず
* .ts でも `// @ts-ignore` が使えるようになった [Suppress errors in .ts files using // @ts-ignore comments](https://github.com/Microsoft/TypeScript/pull/18457)
	* `// @ts-ignore: Unreachable code error` とか書くと次の行のエラーを抑制できる
* `--watch` 時のビルドが早くなった [Speed improvements to --watch](https://github.com/Microsoft/TypeScript/pull/17269)
	* 変更のあったモジュール&関連モジュールだけリビルドされるようになった
* 未使用変数のチェック強化 [Write-only references now flagged as unused](https://github.com/Microsoft/TypeScript/pull/17752)
	* unusedな変数などについて代入のみの場合使ってない判定になるようになった
* 各モジュールでexportされてる要素が入力補完候補に出るようになりimport句も挿入されるようになった [Automatic imports from completion lists](https://github.com/Microsoft/TypeScript/pull/19069)
	* みんなが待ち望んでたやつでは！？
* リファクタリング機能の追加要素
	* 値を `const` として切り出せるやつ [Extract constants/locals in refactorings](https://github.com/Microsoft/TypeScript/pull/18783)
	* JSDocの型注釈をTypeScriptの型注釈に変換 [Convert JSDoc type annotations to TypeScript](https://github.com/Microsoft/TypeScript/pull/18747)
* Quick Fixの追加要素
	* noImplicitAnyで怒られる箇所にコードからの利用箇所に従って型注釈を補う [https://github.com/Microsoft/TypeScript/pull/14786](https://github.com/Microsoft/TypeScript/pull/14786)
	* デコレータを関数呼び出ししたうえで使わないといけなさそうな場合に変換を入れてくれる [Invoke uncalled decorators](https://github.com/Microsoft/TypeScript/pull/18969)
	* `@types` が利用であればインストールしてくれる [Install from @types](https://github.com/Microsoft/TypeScript/pull/19130)
* C#的な `#region` をアウトラインの構成要素としてサポート [Support outlining for // #regions](https://github.com/Microsoft/TypeScript/pull/17954)
* 型定義のコンテキストで `export default` に対して任意の値を指定できなくなった (Add error for using generalized expressions with export assignments in ambient contexts)[https://github.com/Microsoft/TypeScript/pull/18444]
* 直積型(Intersection types)で結果が空になる場合 `never` になるようになった [Remove empty intersection types in unit types](https://github.com/Microsoft/TypeScript/pull/18438)

## 関数の引数の型についてのチェックを強化

いわゆる ~~共変~~ 反変(Contravariant)と言われるやつです。
元々、関数のパラメタについて、TypeScriptは共変&反変(Bivariant)だったのが改められました。

```ts
class Animal {
    bark() {
        return "???";
    }
}
class Cat extends Animal {
    name: string;
    bark() {
        return `${this.name} "meow..."`;
    }
}

// エラーとして検出できるようになった例
let f1: (x: Animal) => string = x => x.bark();
let f2: (x: Cat) => string = x => x.bark();
f1 = f2; // --strictFunctionTypes でエラーになるようになった
f2 = f1; // これは前も今もOK

// これは問題のおこらない操作
let objA: Animal = new Cat();

// しかし関数の引数となるとそうもいかない
// 今まではこの手のミスが検出できなかった
f2 = (x: Cat) => `${x.name} is so pretty!`;
f1 = f2; // f1 の引数は Animal ... nameプロパティがない！
// undefined is so pretty! と出力されてしまう…
console.log(f1(new Animal()));
```

```ts
// こういうのもコンパイルエラーにできるようになった
let toLower = (s: string) => s.toLowerCase();
let p = Promise.resolve<string | undefined>(undefined);
p.then(toLower);
```

`--strictFunctionTypes` オプションとしてこのチェックが導入されました。
`--strict` オプションを指定するとこのオプションも指定したことになるように変更されました。
これはBREAKING CHANGEとなります。

基本的にはこのオプションを有効にしたほうがよいでしょう。
もし、プロジェクトがこの制約に引っかかってしまい、一時的に回避したい場合は `"strictFunctionTypes": false` を指定すると `--strict` が有効な場合でもチェックを迂回することができます。

## タグ付きテンプレートリテラルがキャッシュされるようになった

まぁタイトルのまんまです。

```ts
// query関数 か templateObjectFactory関数 のどちらかにexportが指定されている必要がある(ECMAScriptの仕様ではない)
export function query(x: TemplateStringsArray, ...params: string[]) {
    return x;
}

function templateObjectFactory() {
    return query`/api/foo?name=${"foo=bar"}`;
}
// これがtrueになるようになった
console.log(templateObjectFactory() === templateObjectFactory());

// 同じ文字列を元にしても別のものが出てきちゃう…（辛い）
let escapedUrl1 = query`/api/foo?name=${"foo=bar"}`;
let escapedUrl2 = query`/api/foo?name=${"foo=bar"}`;
console.log(escapedUrl1 === escapedUrl2);
```

lit-htmlというツールで問題になるそうで、そこで問題なくなる範囲で頑張って直したっぽいですね…。
ECMAScriptの仕様との互換性を改善しただけで、完全に準拠できるようになったわけではないようです。

## エラーメッセージの各国語ローカライズがnpmにもshipされるようになった

VisualStudioバンドルのものには結構前からついてた気がするやつです。
リポジトリには入ってたんですがnpm経由で入れるTypeScriptにはバンドルされていませんでした。

```cmd
$ tsc
strictFunctionTypes.ts(16,1): error TS2322: Type '(x: Cat) => string' is not assignable to type '(x: Animal) => string'.
  Types of parameters 'x' and 'x' are incompatible.
    Type 'Animal' is not assignable to type 'Cat'.
      Property 'name' is missing in type 'Animal'.

$ tsc --locale ja
strictFunctionTypes.ts(16,1): error TS2322: 型 '(x: Cat) => string' を型 '(x: Animal) => string' に割り当てることはできません。
  パラメーター 'x' および 'x' は型に互換性がありません。
    型 'Animal' を型 'Cat' に割り当てることはできません。
      型 'Animal' にプロパティ 'name' がありません。
```

こんな感じ。
基本的には英語でやっていきたいですが、見慣れないエラーが出た時はあると役に立つかもしれませんね。

`tsconfig.json` に `"locale": "ja"` を指定することはできないようです。[Issue](https://github.com/Microsoft/TypeScript/issues/19566)

## .ts でも `// @ts-ignore` が使えるようになった

`--allowJs --checkJs` の時に使えるやつがTSでも使えるようになった。

```ts
{
    // @ts-ignore → error TS6133: 'v' is declared but never used.
    let v = 1;
}

// @ts-ignore → error TS6133: 'p' is declared but never used.
function func(p: string) {
}

// コンパイルエラーすら無視できてしまう…！
// @ts-ignore → error TS2345: Argument of type '1' is not assignable to parameter of type 'string'.
func(1);

// 流石に構文エラーは弾いてくれる
// @ts-ignore
));
```

無茶苦茶やな…！

## `--watch` 時のビルドが早くなった

公式の説明によると、ファイルに変更があった時に全部コンパイルするのをやめて、変更があったファイルとそれに関連のあるファイルだけをコンパイルしなおすようになったそうです。
今までやってなかったんかーい！

CommonJSだと依存性解析ができない気がするので、ECMAScript moduleを使っていないと恩恵を受けられないのではないでしょうか(未確認)

他のツール(webpackとかgulpとか)と組み合わせて使っている場合、Roadmapの2.7に `Support for incremental builder compiler API` があるので、もう少し待つ必要があるようです。

## 未使用変数のチェック強化

未使用変数の検出で、2.5までは値の更新(Write)でも未使用フラグを外せてたけどそれができなくなりました。

```
{
    // TypeScript 2.5.1 までは値の更新があれば誤魔化せてた
    // 今はエラーとなる！ error TS6133: 'v' is declared but its value is never read.
    let v = 1;
    v = 2;
}
```

サンプルコードでブロッグを作ってるのは[このバグ](https://github.com/Microsoft/TypeScript/issues/17221)のため。通常exportとかimportが1つはあるので気にしないでよい。

## 各モジュールでexportされてる要素が入力補完候補に出るようになりimport句も挿入されるようになった

![out.gif](https://qiita-image-store.s3.amazonaws.com/0/13283/888e893d-abec-148e-2cc5-7c849303b947.gif "out.gif")


## リファクタリング 値を `const` として切り出せるやつ

任意の値をconstとして切り出せるやつです。
VSCode - Insiders で値を範囲選択してQuick Fixで `Extract to constant in enclosing scope` でできるやつっぽい。

## リファクタリング JSDocの型注釈をTypeScriptの型注釈に変換

そのまんまです。
公式のgifアニメ見ればわかると思います。

動画で使ってたコードを手元（VSCode - Insiders）で試す用として貼っときます。

```ts
/**
 * @param elem {HTMLElement}
 */
function boundingHypotenuse(elem) {
    let { width, height } = elem.getBoundingClientRect();
    return hypotenuse(width, height);
}

function hypotenuse(x, y) {
    return (x ** 2 + y ** 2) ** 0.5;
}
```

`Annotate with type from JSDoc` の他に 次で紹介する `Infer parameter types from usage.` もできてて、とりあえずJSからガガッと移行したい時に便利そう…

## Quick Fix noImplicitAnyで怒られる箇所にコードからの利用箇所に従って型注釈を補う

前述の奴です(相互再帰)。

関数の引数の場合、関数内の実装内部での利用例ではなく、関数の呼び出し部分から型を推論するようです。
この時、該当の関数をexportしている場合、このQuick Fixは使えなくなるようです(ちょっとがっかり)。

```ts
// この場合、x, y ともに number | string に推論される
function plus(x, y) {
    return x + y;
}

plus(1, 2);
plus("a", "b");
```

## Quick Fix デコレータを関数呼び出ししたうえで使わないといけなさそうな場合に変換を入れてくれる

これがエラーになるようになった。

```
function deco(): (...args: any[]) => any {
    return () => {};
}

// error TS1329: 'deco' accepts too few arguments to be used as a decorator here. Did you mean to call it first and write '@deco()'?
@deco
class Foo {
}
```

Quick Fixも提供されています。

## Quick Fix `@types` が利用であればインストールしてくれる

完全に最高のやつです。
npmでもyarnでもとりあえず動くっぽい。
npmの場合、package.jsonとpackage-lock.jsonが更新された。
yarnの場合、package.jsonだけが更新された(？)。

普通にパッケージが存在しない場合はQuick Fixが利用可能にならないっぽいです。

すげーざっと変更差分みた感じ、ネットワークアクセスが絡むコードはエディタ側に処理が投げられてるのでは…？(エディタ側の対応がめんどくさいやつ)

## C#的な `#region` をアウトラインの構成要素としてサポート

なんかあるっぽいです(さほど興味がない)。

## 型定義のコンテキストで `export default` に対して任意の値を指定できなくなった

```ts
declare module "foo" {
  export default 1 + 1;  // should not be allowed
}
```

的な型定義を手で書くとエラーになるようになったらしいです。
今までってそこ式が書けたんだ…。

## 直積型(Intersection types)で結果が空になる場合 `never` になるようになった

```ts
// これは never になる
type T1 = ("A" | "B") & ("C");
// これは "A" になる
type T2 = "A" | "B" & "C";

// これは `"a" & 1` のまま
type T3 = "a" & 1;
```

要するに型の簡約の計算の量を減らすためにneverに落とせる箇所で早めに落とせるようにした、という感じっぽい。
エラーメッセージがわかりやすくなる…というのもありそう。