anti scroll

ブラウザと小説の新しい関係を模索する

Typescriptのアレコレ覚え書き

書いておかないと忘れちゃいそうなので、残しておきます(たまに追記するかも)。

戻り値が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.barundefinedでも、obj.bar?で評価が止まり、全体がundefinedになるわけですね。