Type Challenges 攻略ヒント集
仕事仲間から面白いサイトを教えてもらった。お題に沿ったTypeScriptの型定義を作る問題集のようなサイトだ。
TypeScriptの型定義について知らなかったことが多々あったため、攻略テクニックとして以下にまとめる。
配列型、タプル型をマップする
[string, number]
型から [string[], number[]]
型を得る型を定義したいとする。
// object を定義しそうな見た目だが、結果は配列型 or タプル型になる type ArraysOfArray<T extends any[]> = { [K in keyof T]: T[K][] };
ユニオン型をマップする
string | number
型から string[] | number[]
型を得る型を定義したいとする。
// NG例 ... Tはユニオン型のまま扱われるため (string | number)[] になる type ArraysOfUnion<T> = T[]; // OK例 type ArraysOfUnion<T> = T extends T ? T[] : never; type ArraysOfUnion<T extends keyof any> = { [K in T]: K[] }[T];
参考: 296 - Permutation (with explanations) · Issue #614 · type-challenges/type-challenges · GitHub
プロパティを値でフィルタする
値が string
型であるプロパティのみを抽出したオブジェクトの型を得る型を定義したいとする。
type ExtractStringProperty<T> = { [K in keyof T as T[K] extends string ? K : never]: T[K] };
参考: TypeScript: Documentation - Mapped Types
インターセクション型を集約する
インターセクション型を用いて { a: number; b: string }
を得る型を定義したいとする。
// NG例 ... 実用上は正解だがインターセクション型のままでは不正解となる type AB = { a: number } & { b: string }; // OK例 type AB = Omit<{ a: number } & { b: string }, never>;
型パラメータが never
であるかどうかを判定する
// NG例 ... T が never の場合、結果は true ではなく never になる type IsNever<T> = T extends never ? true : false; // OK例 type IsNever<T> = [T] extends [never] ? true : false; type IsNever<T> = T[] extends never[] ? true : false;