【TypeScript】作成した型の絞り込みを行う

技術的なメモです。


基本的な型の絞り込み

型の絞りこみは TypeScript でなくとも行えますが、
その絞り込みを通知することができます。

if節内部でホバーしてみると分かります。

function juice(fruit: 'apple' | 'orange' | 'grape') {
    if (fruit === 'apple') {
        // ★ fruit が apple であることが認識できる
    }
}

この恩恵を与れる簡単な利用方法です。

タグ付きユニオン型

APIの処理結果など

  • ユニオン型のそれぞれの構造が大きく変わる

場合に利用できます。

type Result = Success | Error
type Success = { data: string }
type Error = { error_message: string, data: string }

fucntion show(result: Result) {
    // Error型のチェック
    // この時点ではSuccess型の可能性があるため、Successにないプロパティの参照は許されない。
    // in を使ってプロパティが存在するかを確認する
    if ("error_message" in result) {
        // ここでError型と推論される
    }
}

in を使った構成でなく、ユニオン型の構成要素に「識別するためのタグ」をつけます。

type Result = Success | Error
type Success = { kind: 'success', data: string }
type Error = { kind: 'error', error_message: string, data: string }

fucntion show(result: Result) {
    // Error型のチェック
    // Success/Errorどちらも kind を共通してプロパティに持っているため、
    // result.kindによるアクセスが行える
    if (result.kind === 'error') {
        // ここでError型と推論される
    }
}

T | should have been removed の改善

const arr = [1,2,3,null];

arr.filter(x => x).map(x => x*2);

このコードは map 内でエラーになります。
変数 arrnumber | null 型であり filter では null を除外しているのですが、
これが認識されず引き続き number | null 型とみなされています。 そのため null との演算が行えずエラーとなります。

このように標準の組み込み関数では除外したはずの型がコンパイラは十分に認識されないことがあります。

この場合、ユーザー型ガードを利用します。

function isNotNull<T>(x: T): x is Exclude<T, null> {
    return x != null 
}

const arr = [1,2,3,null];
arr.filter(isNotNull).map(x => x*2)

自作関数 isNotNullnull の除外を宣言したことで、filter の後では null の可能性がないことを認識してくれます。


移行済(JavaScriptに毛が生えたような any まみれ)のコードで活かす機会は少ないのですが...