TypeScript: Mapped Typesの中身を言語化してみる① [アウトプット全くしてこなかったのでアウトプットする015]


Mapped Types言語化するのが勉強になりそうだとふと感じたのでアウトプットします。

Partial

Partial.d.ts
type Partial<T> = {
    [P in keyof T]?: T[P];
};

ジェネリクスで型Tを受け取り、in keyofでTのkeyをプロパティPに渡しています。
また全てのプロパティはoptional型となります。。

Required

Required.d.ts
type Required<T> = {
    [P in keyof T]-?: T[P];
};

ジェネリクスで型Tを受け取り、in keyofでTのkeyをプロパティPに渡しています。
ここは同じ。だけど[P in keyof T]-?-?の部分でoptional型をなくして必須プロパティにしています。
-?は使ったことがないので自分の引き出しに増えて嬉しい。リバースエンジニアリングをする恩恵です。

Readonly

Readonly.d.ts
type Readonly<T> = {
    readonly [P in keyof T]: T[P];
};

ジェネリクスで型Tを受け取り、in keyofでTのkeyをプロパティPに渡しています。
全てのプロパティに対して読み取り専用のreadonly修飾子をつけています。

Pick

Pick.d.ts
type Pick<T, K extends keyof T> = {
    [P in K]: T[P];
};

Pickには2つのジェネリクスを渡します。
1つ目は型、2つ目は1つ目のジェネリクスに渡した型のサブタイプのプロパティ
[P in K]ここの部分のKには "hoge" | "fuga"のようなプロパティ名が入ってくるのでそれをK extends keyof Tで行っています。
またT[P]で絶対に型情報が欲しいのですが、それはK extends keyof Tで担保されています。

Record

Record.d.ts
type Record<K extends keyof any, T> = {
    [P in K]: T;
};

1つ目のジェネリクスであるKにはどんなプロパティでも渡せます(ただしユニオン型で)。Tには型情報を渡します(こちらも複数の場合はユニオン型で)。
全てのプロパティに対して同じ型情報を渡すというものです。

Exclude,Extract


ExcludeAndExtract.d.ts
type Exclude<T, U> = T extends U ? never : T;
type Extract<T, U> = T extends U ? T : never;

この2つの原理はほぼ同じなので合わせて言語化します。
まず両方ともジェネリクスに2つ渡します。
1つ目の方には型を渡します。2つ目の方にも型を渡していて、
ExcludeはTの型がUのサブタイプであればneverを返す
逆にExtractの方はTの型がUのサブタイプであればTを返す
となっています。

関連記事