TypeScript 1.4.1 変更点

  • 80
    Like
  • 0
    Comment
More than 1 year has passed since last update.

TypeScriptリファレンスお買い上げありがとうございます! Amazon 達人出版会
TypeScript in Definitelylandもよろしくオナシャス!

TypeScript 1.4.1が出ました!
今回のアップデートはかなり多くの更新を含む、大規模なアップデートであると言えます。

公式のBlogにも書かれているのは以下の通り。

  • 型システムの改善
    • Union Types
    • Type Aliases
    • Const Enums
    • And more... (Type GuardsとGenericsの改善)
  • ES6構文のサポートの開始
    • --target es6 の追加
    • Let/Const
    • Template Strings
    • Looking Ahead (async/awaitやってるらしい)

Roadmap上ではExport Language Service public APIと書かれているんだけどアナウンスには含まれてないな…?

あとは、Node.jsが0.12系になってくれれば僕個人としてはわりとes6に移りやすいのですけどもいつになるやら?

型システムの改善

直和型(Union Types)

TypeScript in Definitelylandで既に書いてるので、詳しくはそちらを参照のこと。

最初に書くが TypeScriptで新規にコードを書く時にUnion Typesを使ってはいけない
何故ならば、Union Typesを使ったからってTypeScriptコードの使い勝手がよくなったりするわけではないからだ。
Union Typesは、型定義ファイルを書く時に仕方なく使うのが正しい。
(もちろん、一部例外はある。構文木を書く時などはあると便利だろう。)

例えば、以下のようなJavaScriptコードを考える。

function fizzbuzz(value) {
  if(value % 5 === 0) {
    return "Fizz";
  } else if(value % 3 === 0) {
    return "Buzz";
  } else {
    return value;
  }
}

// [ 1, 2, "Buzz", 4, "Fizz", "Buzz" ] と表示される
console.log([1, 2, 3, 4, 5, 6].map(v => fizzbuzz(v)));

何か普通のFizzBuzzと仕様が違う気がするけどまぁ良い。
これに対して型定義ファイルを書く。
TypeScript 1.3.0までは以下のように書いていた。

declare function fizzbuzz(value: number): any /* string | number */;

返り値の型が、numberstringで、それを表現する手法がなかったのでanyとなる。

今後は普通にこう書ける。

declare function fizzbuzz(value: number): string | number;

また、Union Typesの導入によってBCT(Best Common Type)の仕様が消滅した。
そのため、以下のようなコードの挙動が変わる。

// arrayの型は (number | string)[] になる
var array = [1, "str"];

より安全だ!
実際に要素にアクセスして利用するには、型アサーションが必要になる。
Playground

var array = [1, "str"];
// string か number かわからんので型アサーションが必要
(<string>array[1]).charAt(1);
// これはエラーになる
array[1].charAt(1);

これは流石にめんどくさいし、ヒューマンエラーが入り込む余地がある。
そこで、Union Typesと併せて導入されたのがType Guardsだ。

型のためのガード(Type Guards)

TypeScript in Definitelylandで既に書いてるので、詳しくはそちらを参照のこと。

既にしっかり書いたのに記事として新規に書くのめんどくさくなってきたぞ!端折ろう!

型の別名(Type Alias)

TypeScript in Definitelylandで既に書いてるので、詳しくはそちらを参照のこと。

interfaceと比べると機能的に劣るので極力使うな!

Const Enums

常にインライン展開されることが保証されているenum。
enumの実体は生成されない。コンパイラ上でのみ存在する。
TypeScriptコンパイラ内部に存在するenumはほぼconst enumに置き換えられました。

Playground

enum Fruit {
    Apple,
    Cherry,
    Banana,
}

const enum OS {
    Linux,
    OSX,
    FreeBSD
}

var a1 = Fruit.Apple;
var b1 = OS.Linux;

var a2 = Fruit[Fruit.Apple];
// エラーになる
var b2 = OS[OS.Linux];

これをコンパイルするとこうなる。

var Fruit;
(function (Fruit) {
    Fruit[Fruit["Apple"] = 0] = "Apple";
    Fruit[Fruit["Cherry"] = 1] = "Cherry";
    Fruit[Fruit["Banana"] = 2] = "Banana";
})(Fruit || (Fruit = {}));
var a1 = 0 /* Apple */;
var b1 = 0 /* Linux */;
var a2 = Fruit[0 /* Apple */];
var b2 = OS[0 /* Linux */];

tscのコンパイルオプションに--preserveConstEnumsとか追加されてる。

Genericsの改善

こういうコードがコンパイル通らなくなった。
利用例からの推論に矛盾が生じた場合、エラーになる。
(string | number)とかに推論したりはしない。

function equal<T>(lhs: T, rhs: T): boolean {
   return lhs === rhs;
}

// Previously: No error
// New behavior: Error, no best common type between 'string' and 'number'
var e = equal(42, 'hello');

ES6構文のサポートの開始

--target es6 の追加

es3(default), es5 についで、3つ目のtargetとして追加されました。
es6を指定すると一部の言語仕様が使えるようになります。

let, const

ES6のやつだよ!
既に巷に説明が氾濫していると思うので、そっちを見て、どうぞ。
let, const

Template Strings

この辺見て

tagged template stringsじゃないやつ

var name = "vvakame";
var like = "猫";

var str = `${name}${like}が好き`;
console.log(str);

--target es6でコンパイルした場合

var name = "vvakame";
var like = "猫";
var str = `${name}${like}が好き`;
console.log(str);

--target es5でコンパイルした場合

var name = "vvakame";
var like = "猫";
var str = "" + name + "は" + like + "が好き";
console.log(str);

Cool!

tagged template stringsなやつ

function agreed(strings: TemplateStringsArray, like: string): string {
  var ret = strings[0] + like + strings[1];
  if (like === "TypeScript") {
    ret += "(わかるわー)";
  }

  return ret;
}

// 私はTypeScriptが好き!(わかるわー) と表示される
console.log(agreed`私は${"TypeScript"}が好き!`);

--target es6でコンパイルした場合

function agreed(strings, like) {
    var ret = strings[0] + like + strings[1];
    if (like === "TypeScript") {
        ret += "(わかるわー)";
    }
    return ret;
}
console.log(agreed `私は${"TypeScript"}が好き!`);

--target es5でコンパイルした場合

$ tsc --target es5 test.ts
test.ts(11,19): error TS1159: Tagged templates are only available when targeting ECMAScript 6 and higher.

流石にそこまで面倒見てはくれなかった…

ES6用型定義ファイルの同梱

Promiseとか普通に使える。
--target es6した時だけ使われる型定義ファイルがあるので、全てのターゲットで使えるわけではない。

numberの2進数表記

この辺

こう書ける。

var bin = 0b0101;

console.log(bin);

--target es6でコンパイルした場合

var bin = 0b0101;
console.log(bin);

--target es5でコンパイルした場合

var bin = 5;
console.log(bin);

なお、8進数はes3限定の模様。

shorthand property

この辺この辺

こう書ける。

var num = 1;
var str = "str";
var obj = {num, str};

--target es6でコンパイルした場合

var num = 1;
var str = "str";
var obj = {num, str};

--target es5でコンパイルした場合

var num = 1;
var str = "str";
var obj = { num: num, str: str };

その他

  • --noEmitOnErrorが追加された
    • 今までは型の整合性エラーがあってもソースコードが出力される場合があった
    • なるべく使ったほうが良さそう
  • --suppressImplicitAnyIndexErrorsが追加された
    • インデクスアクセス時に暗黙的にanyになった場合のエラーを抑制できるようになった
    • 基本的には使わないほうがいいと思う
  • TypeScriptコンパイラ本体の型定義ファイルがnpmのモジュールに同梱されるようになった。