is は TypeScript の型推論を補強するユーザー定義型ガードで使われます。
unknown 型や、any 型、Union 型の型の絞り込みを行えます。
スコープ
以下のコードの isString 関数は受け取った引数が string 型かを確認して、boolean 型を返します。
その isString 関数を sam 関数の if の条件で呼び出しています。
そして if 文の a.toUpperCase() の箇所で「’toUpperCase’ は型 ‘number’に存在しません」というエラーが出ています。
function isString(a: unknown): boolean {
return typeof a === 'string'
}
function sam(a: string | number) {
let str: string
if (isString(a)) {
str = a.toUpperCase() //エラー
}
}
isString 関数の実装では、typeof を使って、入力 パラメーターの型を string に絞り込んでいましたが、 型の絞り込みは isString の呼び出し元の sam 関数のスコープには引き継がれません。
TypeScript の推論が理解しているのは、isString 関数が boolean 型を返したということだけです。
なので sam 関数のスコープでの引数 a の型推論は「string | number」である事から、「’toUpperCase’ は型 ‘number’に存在しません」というエラーが出てしまいます。
string であることを、型チェッカーに伝える
isString 関数が呼び出された時、 boolean を返すだけでなく、渡された引数が string であることを、型チェッカーに伝えることが必要です。
ユーザー定義型ガード
ユーザー 定義型ガード(is 演算子)を使う事により、引数の型を絞り込み、boolean を返す関数がある場合、その関数を呼び出すときに引数の型の絞り込みが、スコープが違っても引き継がれていくようにすることができます。
以下コードの戻り値の型が「a is string」となっています。
function isString(a: unknown): a is string {
return typeof a === 'string'
}
「a is string」は isString 関数の結果が true の場合は引数で受け取った変数の型は、string 型であるとTypeScript に教えることができます。
function isString(a: unknown): a is string {
return typeof a === 'string'
}
function sam(input: string | number) {
let str: string
if (isString(input)) {
str = input.toUpperCase() //エラーにはならない
}
}