今回はTypeScriptの組み込み型関数について ※3.4時点
型をしっかり付け始めていろいろと直面する問題が多くそのたびに調べていった結果TypeScriptの組み込み型関数的なものが用意されていることを知りました
これを知らずに自前で型を作ろうとしてむだに考え込んでしまったりとかありそうなので(実際にあった)ある程度把握する
また、ここにある関数を参考に新たになにか作ることもできそうだと思います
TypeScript/lib.es5.d.ts at master · microsoft/TypeScript
Partial
既存の型のすべてが必須ではなくなります
サンプルのとおりですね
interface Hoge { h1: number; h2: string; h3: boolean; } // Partialを通すことで{h1?: number, h2?: string, h3?: boolean}の型が生成される // 全てのキーが必須ではなくなる const hoge: Partial<Hoge> = { h1: 1, h2: 'hoge' }; // h3なくてもok
Required
Partialと反対ですべてのキーが必須になります
interface Hoge { h1: number; h2?: string; } const a: Hoge = { h1: 1 }; // 全てのキーが必須となる // {h1: number, h2: string} の型が生成される const hoge: Required<Hoge> = { h1: 1, h2: 'a' } // ok h1, h2のうち1つでも存在しない場合はNG
Readonly
interface Hoge { h1: number; h2: string; } const a: Hoge = { h1: 1, h2: 'hoge' }; a.h1 = 2; // ok const b: Readonly<Hoge> = { h1: 1, h2: 'a' }; b.h1 = 2; // Error
見ての通りReadonlyなので各要素を書き換えできなくなる型が生成されます
個人的には基本的に常にReadonlyを付けておいたほうが良いと思います
これはネストしたハッシュに対してReadonlyにしたらよさそう?!とおもい調べてみたらすでにそういうライブラリもあるようですね
immutability - DeepReadonly Object Typescript - Stack Overflow stackoverflow.com
krzkaczor/ts-essentials: All basic TypeScript types in one place 🤙 github.com
Pick
interface Hoge { a: number; b: string; c: number; } interface Fuga { a: number; b: string; } const a: Hoge = { a: 1, b: 'hoge', c: 3 }; // keyof Fuga -> a | b // Pick<Hoge, keyof Fuga> -> {a: number, b: string} // Hogeからa,bが取り出された新たな型が生成される const b: Pick<Hoge, keyof Fuga> = { a: 1, b: 'hoge', c: 2 // Error };
個人的に一番良く使いそうだとおもうPickです
ある型から特定のキーだけ抜き出した型を生成するための関数です
既存コードで「だいたい同じだけど少しだけ違う」みたいなパターンでつかえそうです
Record
type HogeRecord = Record<'h1'|'h2', string>; // {h1: string, h2: string}の型が生成される const hoge: HogeRecord = { h1: 'hoge', h2: 'fuga', };
最初上記の使いみちのみと勘違いしてとくに使いみちが。。。と思っていたのですが下記のような使い方もできるようです
type FugaRecord = Record<'hoge'|'fuga'|'piyo', {id: number, name: string}> const samples: FugaRecord = { hoge: {id: 1, name: 'hoge'}, fuga: {id: 2, name: 'fuga'}, piyo: {id: 3, name: 'piyo'} }; // ok // hoge,fuga,piyo以外のキーを足すとエラー // オブジェクトにid,name以外を足すとエラー // idを数値以外、nameを文字列以外にするとエラー interface ReportRow { id: number; name: string; } type Category = 'c1'|'c2'; type ReportRecord = Record<Category,ReportRow[]> const rows: ReportRecord = { c1: [{id: 1, name: 'hoge'}, {id: 2, name: 'fuga'}], c2: [{id: 3, name: 'piyo'}], c3: [{id: 4, name: 'foo'}] // Error };
これもデータの持ち方次第なきもしないでもないですが・・・
あるカテゴリ毎に同じようなレコードがある場合とかに使える感じですかね
ただできることはわかったので後は今後適切な場所で使うことができればOK
Exclude, Extract
type Hoge = 'a'|'b'|'c'; type Fuga = 'c'|'d'|'e'; type ExcludedHoge = Exclude<Hoge, Fuga>; // a|b|c - c|d|e -> a|b type ExtractedHoge = Extract<Hoge, Fuga>; // a|b|c & c|d|e -> c const a: ExcludedHoge = 'c'; // Error const b: ExtractedHoge = 'a' // Error
こちらは第一引数の型から第二引数の型をどうするか
サンプルコードまんまですね
ExcludeはHogeからFugaを引いたもの
ExtractはHogeとFuga両方にあるもの
Pickなどで特定のキーのデータのみ抽出したいとかそういう場合の特定キーの抽出に使えそう
NonNullable
type Fuga = 'a'|'b'|null|undefined; // null, undefinedが除外される const a: NonNullable<Fuga> = 'a'; const b: NonNullable<Fuga> = 'b'; const c: NonNullable<Fuga> = null; // Error const d: NonNullable<Fuga> = undefined; // Error
与えられたリストからnull,undefiendを除いた型を返す
こちらもサンプル見たまんまですね
Parameters
const hogeFn = (arg1: number, arg2: string, arg3: boolean): void => {}; const fugaFn = (arg1: number): void => {}; type HogeParams = Parameters<typeof hogeFn> // [number, string, boolean] type FugaParams = Parameters<typeof fugaFn> // [number] // 関数の引数の型を生成する // typeof FunctionName で渡すが関数以外のtypeofを渡すとエラーになる const a: HogeParams = [1, 'a']; // Error const b: HogeParams = [1, 'a', false]; // ok const c: FugaParams = [1]; // ok const d: FugaParams = [1, 'a']; // Error
関数を渡す型関数ですね
関数への引数の型をそのまま型にして返してくれます
関数呼び出し時にこのParameterを使えば関数のIFに変更があってもよしなに気づくことができる感じになりそうですね
ConstructorParameters
class Animal { constructor(hoge: number, fuga: string){ } } type Hogeparams = ConstructorParameters<typeof Animal>; const a: Hogeparams = [1, 3]// Error const b: Hogeparams = [1, 'hoge']// ok
Parametersとほとんど同じでこちらはConstructorの引数を型とする関数
ReturnType
const HogeFn = (args1: number): string => { return 'hoge' } type Hoge = ReturnType<typeof HogeFn> const a: Hoge = 1; // Error const b: Hoge = 'a';
関数の戻り値の型を生成する関数
InstanceType
やってることはわかるけどどこで使うかピンとこなかったです
下記issueでこういうときに有用だよという議論がされているので一応リンクだけ張っておきます
Need documentation for InstanceType · Issue #25998 · microsoft/TypeScript
まとめ
これだけでも知っていたら便利に使えるときが来そうに思います
実際こういうのが必要になっていろいろ調べたので必要なはずですw
この「型をゴニョゴニョして新たな型を生成する」系の操作はメタプロっぽくて個人的には面白くなってきています
あんまりやりすぎると書いた人以外わからなくなりそうですが・・・
組み込み型関数くらいであれば同じような記述が減らせてコード書くのも楽になりそうですね