書いておかないと忘れちゃいそうなので、残しておきます(たまに追記するかも)。
戻り値が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
になるわけですね。