Edited at

TypeScript 2.6.1 変更点

More than 1 year has passed since last update.

訂正1: コメントで指摘があった Contravariant→反変では? を反映。cocontra

こんにちはソウゾウ社に転職しました@vvakameです。

今回は結構気持ちよくなる更新が多いです。

TypeScript 2.6.1がアナウンスされました。

What's new in TypeScriptも更新されているようです。

破壊的変更もあるよ!


変更点まとめ


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

いわゆる 共変 反変(Contravariant)と言われるやつです。

元々、関数のパラメタについて、TypeScriptは共変&反変(Bivariant)だったのが改められました。

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

// こういうのもコンパイルエラーにできるようになった

let toLower = (s: string) => s.toLowerCase();
let p = Promise.resolve<string | undefined>(undefined);
p.then(toLower);

--strictFunctionTypes オプションとしてこのチェックが導入されました。

--strict オプションを指定するとこのオプションも指定したことになるように変更されました。

これはBREAKING CHANGEとなります。

基本的にはこのオプションを有効にしたほうがよいでしょう。

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


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

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

// 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にはバンドルされていませんでした。

$ 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


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

--allowJs --checkJs の時に使えるやつが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;
}

サンプルコードでブロッグを作ってるのはこのバグのため。通常exportとかimportが1つはあるので気にしないでよい。


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

out.gif


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

任意の値をconstとして切り出せるやつです。

VSCode - Insiders で値を範囲選択してQuick Fixで Extract to constant in enclosing scope でできるやつっぽい。


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

そのまんまです。

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

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

/**

* @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は使えなくなるようです(ちょっとがっかり)。

// この場合、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 に対して任意の値を指定できなくなった

declare module "foo" {

export default 1 + 1; // should not be allowed
}

的な型定義を手で書くとエラーになるようになったらしいです。

今までってそこ式が書けたんだ…。


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

// これは never になる

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

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

要するに型の簡約の計算の量を減らすためにneverに落とせる箇所で早めに落とせるようにした、という感じっぽい。

エラーメッセージがわかりやすくなる…というのもありそう。