書いておかないと忘れちゃいそうなので、残しておきます(たまに追記するかも)。
戻り値がbooleanであると同時に、引数が特定の型であることをコンパイラに教えることができる
これが便利なのは、こういう感じのコードにおいてです。
class Foo { say(){ console.log("foo"); } } let isFoo = (val: any): boolean => { return val instanceof Foo; }
このisFooを使って、ある値の型がFooである場合に(Fooのメソッドである)sayを呼ぶ、といった処理を書きたくて
let func = (val: any) => { if(isFoo(val)){ val.say(); // val は any なのでエラー } }
などとやると、コンパイル・エラーが出ます。上のコードでは(当たり前ですが)valの型がanyとみなされるからです。
しかしこれでは、せっかくFooであることを確認するisFoo関数の意味がなくなってしまいます。
しかしこの問題は、isFooを、次のように書き換えることで解決します。
let isFooEx(val: any): val is Foo { return val instanceof Foo; }
戻り値の型の部分に記述されたval is Foo の働きによって、引数のvalの型は呼び出し元にFooだよ、と認識され、次のコードが通るようになります。
let func(val: any){ if(isFooEx(val)){ val.say(); // val は Foo なのでOK! } }
このval is Fooの部分のことを、Type Guard と呼ぶのだそうです。
詳しくは、Type Guards and Differentiating Types を参照して下さい。
型引数にもデフォルト値を設定できる
TypeScript 2.3からですが、次のような感じで型パラメータにデフォルト値を設定できるようです。
class Component<Props = any, State = any> { props: Props; state: State; } type StateActionPair<T, V extends Action = Action> = { state: T | undefined; action?: V; };
二番目の例にあるV extends Action = Action の部分は、Actionの部分型であるVのデフォルト型はActionである、という意味です。
これまでこういったことを知らなくて、色々と汚いコードを書いてました…反省。
Nullチェックを無視させることができる
nullが入り得る型なんだけど、そのチェックがいらないことが明らかな場合、コンパイラにnullチェックを無視させることができます。
let foo = (entity?: Entity): string { return entity!.name; }
entity!という部分がそれです。
上のプログラムにおいてentityという引数は、Entity型もしくはnullもしくはundefinedになる恐れのある引数だ、と言ってるので、普通にentity.nameと書くと、コンパイルエラーになります(ただし--strictNullChecksが有効時)。
しかしこういうnullなどになり得る変数のあとに!をつけると「ここは特別にnullにならないからチェックしなくて良いよ!」という意味になります。
これも使えると時々は便利です。
参考:Non null assertion operator
undefinedならプロパティアクセスさせず全体をundefinedにする演算子
例えばこんなオブジェクトがあるとして
const obj: any = { foo: { bar: 'bar' } };
次のようにアクセスするとエラーになります。
const value = obj.bar.bar // Cannot read property 'bar' of undefined
こういう木構造の途中がundefinedかもしれないものにアクセスするときに、いちいち
const value = obj.bar? obj.bar.bar : undefined;
みたいに書くのは面倒ですよね。しかし?演算子を使うと、これを
const value = obj.bar?.bar;
というように、短く書くことができます。
仮にobj.barがundefinedでも、obj.bar?で評価が止まり、全体がundefinedになるわけですね。