Typescript UtilityTypes まとめる
React に続き TypeScript も今週から始めてみたけど、おもろい!型がおもろい!カタが! UtilityTypes について、少しずつ分析してみる。
Exclued
U に割り当て可能な T のキーを全て exclued (除外)した T を構築
type Exclude<T, U> = T extends U ? never : T
Tをstring 、Uを number とした場合
extends ? の結果 string は number の部分型ではないため false。
よって string から 除外されるものはなく、そのままプリミティブ型の string となる。
type E = Exclude<string, number> // E の型は プリミティブ型 string const obj: E = "sample"
TをSample 、UをExample とした場合
keyof によるそれらの union 同士のextends ? において、U に対して T の name が部分型であるため true。
よって name が never となり、それ以外の age が T となる。
type E = Exclude<keyof Sample, keyof Example> // E の型はリテラル型 "age" const obj: E = "age" type Sample = { name: string age: number } type Example = { name: string weight: number }
Omit
TからKをOmit (省く)したオブジェクトにマッピング
Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; }
Pick と逆の動作 (Pick はTからKを選んでマッピング)
シグネチャの通り、string | number | symbol の部分型のみ省くことが可能
Exclued が使用されている
// 上の方に書いた Exclued のシグネチャ Exclude<T, U> = T extends U ? never : T // Omit ではその変化球 // Exclude の T を keyof の union 、U を K で表しており、全体としてMappedTypes である type Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; }
Omit の T を Sample、 その中から省きたい K を "name" | "age" とした場合
Exclued の K である "name" | "age" に割り当て可能な Sample である T の keyof による union は、Sample の構造より、name, age となる。
そのため、それらが除外され weight が残る。
Omit<Sample, "name" | "age"> type Sample { name: string, age: number, weight: number }
残った weight は P に掛かっており、その型は T[P]であらわすことから 、つまりMappedTypes であり、in によって P が weight 、T[P] の評価により、その型は number のオブジェクトにマッピングされる。
// 型引数を決める前 type Omit<T, K extends string | number | symbol> = { [P in Exclude<keyof T, K>]: T[P]; } // 型引数を決めた後 Omit<Sample, "name" | "age"> = {weight: number} // O の型は {weight: number} 型 type O = Omit<Sample, "name" | "age"> // Sample から name, age が省かれるため weight のみ指定できる const obj: O = {weight: 4.8}