機能的にはもうかなり充実してきたので「もう次の出たの」みたいな感想になってきました。
こんばんは@vvakameです。
TypeScript 2.2がアナウンスされましたね。
What's new in TypeScriptも更新されているようです。
変更点まとめ
- クラスのMixinパターンのサポートMixin classes
- 特定のコンストラクタパターンを持つクラスについてMixinパターンのbaseに指定できるようになった
- TypeScript的に自然な型の導出が行われるのが良いという話
- インタフェースが object-like typeならなんでも拡張できるようになった Allow deriving from object and intersection types
- type aliasと組み合わせできなかったのができるようになった
- intersection typesはOKだけどunion typesはだめ
- intersection typesでの
this
型はそれ自身を指すにようなった
-
new.target
がサポートされた Support for new.target- ES2015で追加されたやつ
- nullableな値に対する演算子の適用でよいよいチェックを提供Improved checking of nullable operands in expressions
-
undefined + 1
とかになりうるコードを書くと教えてもらえる
-
- クラスの継承にObject.setPrototypeOfを使うようになった Update __extends to use Object.setPrototypeOf
- Babel製クラスのフィールドが意図通り継承できない問題を解決
- stringインデックスシグニチャに対する
.
アクセスの挙動を改善Allow property (dotted) access for types with string index signatures- 今までは
hoge["fuga"]
とhoge.fuga
でコンパイル時のチェックされかたに差があった
- 今までは
- JSXで子要素のspread記法がサポートされたSupport for JSX spread children
-
<TodoList {...x} />
こんなんとからしい
-
- JSX記法のターゲットにReact Nativeが追加されたNew --jsx react-native
- preserveとreactの合体みたいな感じっぽい?
-
object
型のサポート Support for the object type- 新プリミティブ型
-
Object.create('string')
とかをちゃんとエラーにしたかった - 要するにObjectかその他のプリミティブかを区別したかった
- Language Service経由で使えるQuick fixesの種類が増えた。More Quick fixes!
- 使ってるシンボルがスコープになかったら適切なimport句を補ってくれる Add missing imports
- インタフェースや抽象クラスの足りないメンバを補ってくれる Implement interface/abstract class members
- 使ってないシンボルを削除してくれる Remove unused declarations
-
this.
が足りない時に補ってくれる Add missing this. - アクセスしてるのに存在してないプロパティを補ってくれる Add missing property declaration
クラスのMixinパターンのサポート
すごい端的に言うと { new (...args: any[]): A } & { new (s: string): B }
は { new(s: string): A & B }
に簡約してもいいというルールが追加されたという話。
type Constructor<T> = new (...args: any[]) => T;
function Tagged<T extends Constructor<object>>(Base: T) {
return class extends Base {
tag = "";
constructor(...args: any[]) {
super(...args);
}
};
}
class Score {
constructor(public point: number) { }
}
// mixinできる
const TaggedScore = Tagged(Score);
// これはちゃんと怒られる
// error TS2345: Argument of type '"s"' is not assignable to parameter of type 'number'.
// new TaggedScore("s");
const ts = new TaggedScore(1);
ts.tag = "vv";
console.log(ts.tag, ts.point);
// mixinしたクラスを継承もできる
class RankingScore extends TaggedScore {
constructor(public rank: number, tag: string, point: number) {
super(point);
this.tag = tag;
}
}
const rs = new RankingScore(1, "vv", 100);
console.log(rs.rank, rs.tag, rs.point);
Mixin用の関数は先頭大文字にするんですかね…?
インタフェースが object-like typeならなんでも拡張できるようになった
すごい端的に言うと、インタフェースはインタフェースを拡張できる(前から)。インタフェースと見做される範囲が拡張された。
type T1 = { a: number };
type T2 = T1 & { b: string };
type T3 = () => void;
type T4 = [string, number];
interface I1 extends T1 { x: string } // オブジェクトリテラルの拡張
interface I2 extends T2 { x: string } // intersection typesの拡張
interface I3 extends T3 { x: string } // 関数の拡張
interface I4 extends T4 { x: string } // タプル型の拡張
let obj1: object = null as any as T1;
let obj2: object = null as any as T2;
let obj3: object = null as any as T3;
let obj4: object = null as any as T4;
type T5 = string;
type T6 = T1 | { b: string };
interface I5 extends T5 { x: string } // primitive型は拡張できない
interface I6 extends T6 { x: string } // union typesは拡張できない
let obj5: object = null as any as T5;
let obj6: object = null as any as T6; // objectと互換性があるかという基準ではないらしい
intersection typesを含む型パラメータ付きのtype aliasも継承できるようになった。
type Named<T> = T & { name: string };
interface N1 extends Named<T1> { x: string } // { a: number, name: string, x: string }
interface N2 extends Named<T2> { x: string } // { a: number, b: string, name: string, x: string }
// 標準で入ってるPartialを使った型も継承できるようになった
interface P1 extends Partial<T1> { x: string } // { a?: number | undefined, x: string }
つよい。
また、 this
が表す型がintersection typesの場合、定義されている型だけじゃなくて本当にintersection types自身を指すようになった。
interface Thing1 {
a: number;
self(): this;
}
interface Thing2 {
b: number;
me(): this;
}
function f1(t: Thing1 & Thing2) {
// Thing1 & Thing2 が返ってくる
// 以前は Thing1 だった…(のでコンパイルエラー
t = t.self();
// 同上
t = t.me().self().me();
}
先のMixinのルールと組み合わせて以下のようなコードがコンパイルが通るようになった。
type Constructor<T> = new (...args: any[]) => T;
class Base extends (1 as any as Constructor<object>) {
}
// 当たり前だけど実行時エラー anyにキャストした報いを受けよ!
// Uncaught TypeError: Object prototype may only be an Object or null: 1
new Base();
このコードだけだと間違った例なのでアレなんだけど、3rd partyライブラリを使っている時にこういう操作を稀にしたい時があったのでこれが受け入れられるようになったのは喜ばしい…!
new.targetがサポートされた
コレです。
されました(終わり
class A {
constructor() {
console.log(new.target.name);
}
}
// A と出力される
new A();
Custom ElementsなどHTMLElementを扱う時、どうしても new.target
が使えないと困る場合というのが極稀に人生で2回くらいあるそうなのでよかったですね。
nullableな値に対する演算子の適用でよいよいチェックを提供
undefined + 1
とかが怒られるようになってよかったねみたいな話。
// だめ
null + 1;
1 + null;
// OK (anyとstringのみ)
null + (1 as any);
null + "";
"" + null;
// --strictNullChecks有りだとこの後全部だめ
let n: number | null = null as any;
n - 1;
1 - n;
n * 1;
n ** 1;
n / 1;
n % 1;
n << 1;
n >> 1;
n >>> 1;
n & 1;
n | 1;
n ^ 1;
n < 1;
n > 1;
n <= 1;
n >= 1;
let obj: {} | null = null as any;
"v" in obj;
let D: typeof Date | undefined = null as any;
let v = obj instanceof D;
+n;
-n;
~n;
++n;
--n;
クラスの継承にObject.setPrototypeOfを使うようになった
すごい端的に言うと、Babel製クラスのスタティックメソッドがTypeScriptから継承できなくて困ったので直しましたという話。
ES2015的にクラスのメンバ(メソッドとか)は enumerable: false
なんだけどTypeScriptは enumerable: true
なコードを生成してしまう。
TypeScriptで書いたクラスをTypeScriptで継承するクラスを書くのは特に齟齬が発生しない。
しかし、Babelは仕様どおり enumerable: false
なコードを吐くので、Babel製クラスのスタティックメンバをTypeScriptで継承しようとすると enumerable: true
である前提のコードが吐かれて困ってしまっていた。
これはSkateJSで問題になったりして困った。
困ったので僕が直しました。褒めてほしい。
この辺の苦労話はC91で書いたので買って欲しい(宣伝
stringインデックスシグニチャに対する .
アクセスの挙動を改善
謎の制約が解除されてよかったねって感じ。
interface A {
exists: boolean;
[other: string]: number | boolean;
}
let obj: A = { exists: true };
// これはOK
obj["exists"] = false;
obj["unknown"] = 1;
obj.exists = false;
// これは何故かTypeScript 2.1.xまでダメだった
// error TS2339: Property 'unknown' does not exist on type 'A'.
obj.unknown = 1;
JavaScript的に自然に書けなくて微妙だったのが改善された。
てっきりindex signatureなんか使うなよ気持ち悪い構文強制させて反省を促すぞ!みたいな話だと思ってた。(半分くらい本気
JSXで子要素のspread記法がサポートされた
わかめさんもSkateJSをちょいちょい書くようになったので多少はJSX(TSX)に興味が出てきたんですがふーんって感じです。
ArrayなものはちゃんとArrayに見えるように記述できると構文解析的にチェックが正しく行いやすくなって嬉しいみたいな話かしら。
自分でIssue読んで下さい。
JSX記法のターゲットにReact Nativeが追加された
なんか特別な何かなのかと思ったけどIssue見ると拡張子の出力の仕方がReact Nativeと親和性よくなるみたいな話で謎の魔術が追加導入されたということではなさそうだった。
--jsx react-native
オプション。
object型のサポート
string
boolean
number
の他に object
を増やして解決できる問題を増やそう!という話。
例えば Object.create("str")
とかすると Uncaught TypeError: Object prototype may only be an Object or null: str
とか言って怒られる。
これは既存のTypeScriptの型チェックだと検出できなかった。
ここに、新たに object
primitiveを加える事により、object
じゃないもの という概念が発生してこれを上手く弾く事ができるようになるという話。
Object.create("test");
Object.setPrototypeOf({}, "test");
など(少ない
keyofとかも多分そうなんですが、言語に多少の複雑さを持ち込んででも現実的JavaScriptの問題を手軽かつ静的に解決する事にマジで心血を注いでいる形なので偉いと思います(こなみ
Language Service経由で使えるQuick fixesの種類が増えた
Language Service組込です。
- 使ってるシンボルがスコープになかったら適切なimport句を補ってくれる
- インタフェースや抽象クラスの足りないメンバを補ってくれる
- 使ってないシンボルを削除してくれる
- this.が足りない時に補ってくれる
- アクセスしてるのに存在してないプロパティを補ってくれる
http://code.visualstudio.com/
VisualStudioCodeのInsiders版を使うと試す事ができます。
Macだと ⌘+.
でQuick Fixが使えました。
公式の紹介の動画もわかりやすいですね。
らこらこにこんなんできるようになったよ!!って見せたら「やぁっとWebStormに追いついてきましたか…」 って言われた。