TypeScriptのユーティリティ型を実装する Part1

# はじめに
TypeScriptでよく行われる型変換をサポートするために、TypwScriptでは[ユーティリティ型](https://www.typescriptlang.org/docs/handbook/utility-types.html)というものを提供しています。この記事ではそんなユーティリティ型を再実装してみようと思います。
全部で21ケースありますが、1ケース(`ThisType`)は単なる空のマーカーインターフェイスで、4ケースはintrinsic型(TypeScriptのコンパイラに隠された型)なので残りの16ケースを紹介します。数が多いのでこの記事では6ケース紹介して、残りの10ケースは別記事に分けて紹介します。Part2は[こちら](https://qiita.com/KokiSakano/items/3b7dc5f8f1c905cdfe2d)です。Part3は[こちら](https://qiita.com/KokiSakano/items/1e78528383d2b53943b5)です。

# Awaited
`Awaited`はaync関数のawaitや、Promiseにおけるthenのような操作の結果を再起的に取得するような型です。
```ts
type Example01 = Awaited<Promise<string>>
```
とすれば`string`を取得することもできますし、
```ts
type Example02 = Awaited<Promise<string | Promise<number>>
```
とすると`string | number`を得ることが出来ます。
このような関数を作るにはPromiseに渡される引数をPromiseが完全に剥がれるまで取得すれば良いので以下のように書くことで再現することが出来ます。
```ts
type MyAwaited<T> = T extends Promise<infer U> ? MyAwaited<U> : T;
```
`T extends Promise<infer U>`でTがPromiseだった時にはその中身`U`を取得するようにしています。そして`MyAwaited<U>`は取得した`U`を再度自作した`MyAwaited`に代入しています。これをPromiseではなくなるまで繰り返して、Promiseでは無くなったときに`T`そのものを返しています。
再実装を紹介したところでTypeScriptの実装を見てみます。
```ts
type Awaited<T> =
    T extends null | undefined ? T :
        T extends object & { then(onfulfilled: infer F, ...args: infer _): any } ?
            F extends ((value: infer V, ...args: infer _) => any) ?
                Awaited<V> :
                never :
        T;
```
再実装したものと比べて難解な表現ですが、基本的に行なっていることは同じです。TypeScriptの実装ではPromiseから中身を取得するのではなく、Promiseが持つthenメソッドから中身を取得するようになっています。これによってPromiseの他のPromiseLikeなどのThenableな型に対応することができるわけです(つまり再実装の例ではPromiseLikeなどは扱えません)。
型の説明です。まず`T`が`null`と`undefined`である場合はすぐにその値を返します。そして`T`がThenableな型だった場合は引数`onfulfilled`を`V`として取得します。取得できなかった場合は非同期の型ではないと判断して`T`を返します。`V`は`onfulfilled`関数の型で以下のようになっています。
```ts
onfulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null
```
`undefined`や`null`の場合を除けば関数の形になっているとして`F extends ((value: infer V, ...args: infer _) => any)`で`V`(Promiseの中身)を抜き出します。そしてさらに`V`を`Awaited`に渡してThenableではなくなるまで処理を続けます。
# Partial
`Partial`は渡されたオブジェクトをオプショナルな型にします。
例えば
```ts
type User = {
  id: number;
  name: string;
  mailaddress: string;
};
type PartialUser = Partial<User>;
```
のように使うことが出来ます。結果としては以下のようなものが得られます。
```ts
{
  id?: number | undefined;
  name?: string | undefined;
  mailaddress?: string | undefined;
};
```
オプショナル化は再起的には行われず、浅い階層に対してのみ行われます。つまり下のような型は
```ts
type Admin = {
  id: string;
  type: string;
  user: {
    id: number;
    name: string;
    mailaddress: string;
  };
};
type PartialAdmin = Partial<Admin>;
```
以下のようになります。
```ts
{
  id?: string | undefined;
  type?: string | undefined;
  user?: {
    id: number;
    name: string;
    mailaddress: string;
  } | undefined;
}
```
このようなオブジェクトに作用させる処理は[Mapped Types](https://www.typescriptlang.org/docs/handbook/2/mapped-types.html)で大体は解決できます。この機能を利用すれば以下のように実装できます。
```ts
type MyPartial<T> = {
  [P in keyof T]?: T[P];
};
```
オブジェクトを組み直す際に`?`をつけて一つずつオプショナル化するだけです。この実装はTypeScriptの実装とも一致します。
# Required
`Required`は先ほどの`Partial`がオプショナル化するのに対して必須にする型です。
```ts
type PartialUser = {
  id?: number | undefined;
  name?: string | undefined;
  mailaddress?: string | undefined;
};
type User = Required<PartialUser>;
```
上記の例はお察しの通り以下のようになります。
```ts
{
  id: number;
  name: string;
  mailaddress: string;
};
```
浅い階層にしか処理が走らない振る舞いも同じです。
実装も`Partial`とほとんど同じです。
```ts
type MyRequired<T> = {
  [P in keyof T]-?: T[P];
};
```
`-?`とすることでオプショナルが解けるというわけですね。TypeScriptの実装も同じようになっています。
# Readonly
`Readonly`も`Partial`や`Required`と似た型です。オブジェクトに対して作用させる型で、そのオブジェクトを浅い階層で`readony`にします。`Partial`や`Required`と異なる点として、配列に対しても有効な型となっています(厳密には`Partial`も`Required`も配列に対して作用しますが、利用する時がほとんどないので考えないものとしています)。
```ts
type Sample01 = Readonly<[number]>;
```
上記の例では`readonly [number]`が結果とされます。
実装方法は`Partial`などに似ていて以下のように行えます。
```ts
type MyReadonly<T> = {
  readonly [P in keyof T]: T[P];
};
```
配列の実装はキーが`number`のオブジェクトのように扱えるので、実装時には配列の考慮を行わなくても良いです。
これもまたTypeScriptも同じ実装になっています。
# Record
`Record`は`Record<Keys, Type>`のような引数ととり、`Keys`に渡したユニオンのそれぞれをキーとしてそれらが`Type`をバリューとするプロパティを持つオブジェクトを作成する型です。
```ts
type User = {
  id: string;
  name: string;
  mailaddress: string;
};
```
を作りたい時は以下のように利用します。
```ts
type User = Record<'id' | 'name' | 'mailaddress', string>;
```
実装はこれまでになく簡単に行えます。`Keys`を元にキーを組み立て、`Type`をバリューにするだけだからです。
```ts
type MyRecord<Keys extends keyof never, Type> = {
    [P in Keys]: Type;
};
```
TypeScriptとの違いは引数の命名の違いと、`keyof never`が`keyof any`になっている箇所くらいです。`keyof never`も`keyof any`もどちらも`string | number | symbol`なので意味していることは同じです。

# Pick
`Pick`は`Pick<Type, Keys>`のように使います。`Keys`は`Type`のキーの一部で、`Pick`は`Type`から`Keys`に指定されたキーのプロパティのみを抜き出す型です。
```ts
type User = {
  id: string;
  name: string;
  mailaddress: string;
};
type PickedUser = Pick<User, 'id' | 'name'>;
```
のようにすると`PickedUser`は以下のような値になります。
```ts
{
  id: string;
  name: string;
}
```
実装は以下のようにします。
```ts
type MyPick<Type, Keys extends keyof Type> = {
  [P in Keys]: Type[P];
};
```
`Type`から`Key`だけを取得するように展開しました。これも型名は異なりますが、TypeScriptの実装と同じです。