【TypeScript】Utility Typesをまとめて理解する

# Utility Typesとは
`Utility Types`とはコード内で型変換を容易にする為にTypeScriptが提供する(便利な関数のような)型達です。

# Partial`<T>`
`Partial<T>`は`T`の全てのプロパティをOptional(任意)のプロパティにしてくれます。
下記のコード`Person`では１つも任意のプロパティが設定されていませんが、`Partial<T>`を使用する事で、変数`taro`では`firstName`のみを持つ事ができています。

```ts
interface Person {
  firstName: string
  lastName: string
  age: number
}

const taro: Partial<Person> = {
  firstName: 'Taro',
}
  
console.log(taro); //=> { firstName: 'Taro' }
```

# Required`<T>`

`Required<T>`は`T`の全てのプロパティを必須のプロパティにしてくれます。
下記のコード`Person`では全てが任意のプロパティが設定されていますが、`Required<T>`を使用する事で、変数`jiro`では`firstName`と`lastName`の両方を与えてあげないと、エラーが発生します。

```ts
interface Person {
  firstName?: string
  lastName?: string
}

const jiro: Required<Person> = {
  firstName: 'Taro',
} 
// Error: property 'lastName' is missing.
```

# Readonly`<T>`
`Readonly<T>`は`T`の全てのプロパティを`readonly`のプロパティにしてくれます。
下記では`Readonly<Todo>`としているため、`Todo`のオブジェクトである`todo`の`title`を更新しようとするとエラーが発生します。

```ts
interface Todo {
  title: string
}
const todo: Readonly<Todo> = {
  title: '家の掃除',
}
todo.title = '夕飯の買い出し' // Cannot assign to 'title' because it is a read-only property.ts(2540)
```

# Record`<K, T>`
`Record<K, T>`は`K`がプロパティとなり`T`型を持つレコード型を構築します。
言葉ではややわかりずらいので、下記の例を元に考えています。
　
`Record<K, T>`の`K`には`number`が指定されています。そして、`T`には`User`が指定されています。
このことから、`Record<K.T>` を使用して作成された`UserList`型は`number`型がプロパティとなり、`User`をもつ型となります。

```ts
interface User {
  name: string
}
type UserList = Record<number, User>

const list: UserList = { 0: { name: 'Taro' }, 1: { name: 'Jiro' } }
console.log(list) //=> { '0': { name: 'Taro' }, '1': { name: 'Jiro' } }

```

# Pick`<T,K>`
`Pick<T,K>`は既に存在する`T`型の中から`K`で選択した一部のプロパティのみを含んだ新たな型を構築します。
下記の例では、`Todo`の`title`と`completed`のみを含んだ新たな型`TodoPreview`を作成しています。

```ts
interface Todo {
  title: string
  description: string
  completed: boolean
}
type TodoPreview = Pick<Todo, 'title' | 'completed'>

const preview: TodoPreview = {
  title: '部屋の掃除',
  completed: false,
}
console.log(preview) //=> { title: '部屋の掃除', completed: false }
```

# Omit`<T,K>`
`Omit<T,K>`は既に存在する`T`型の中から`K`で選択した一部のプロパティを除いた新たな型を構築します。
下記の例では、`Todo`から`description`を抜き取って、新たな型`TodoPreview`を作成しています。

```ts
interface Todo {
  title: string
  description: string
  completed: boolean
}
type TodoPreview = Omit<Todo, 'description'>

const preview: TodoPreview = {
  title: '部屋の掃除',
  completed: false,
}
console.log(preview) //=> { title: '部屋の掃除', completed: false }
```

# Exclude`<T,U>`
Exclude<T,U> は`T`型のプロパティで`U`型に代入可能なプロパティを取り除いた型を構築します。
下記の例では、
`ExcludedType`では`"id" | "name"`から`"id" | "address"`に代入可能な`"id"`を取り除いた型を作成しています。
`ExcludedType2`では`string`は`number`に代入可能では無いので、`string`となります。
`ExcludedType3`では`string | number | boolean`で唯一`string | boolean`に代入可能では無い`number`となります。

```ts
interface TypeA {
  id: number
  name: string
}
interface TypeB {
  id: number
  address: string
}

type ExcludedType = Exclude<keyof TypeA, keyof TypeB> // "name"
type ExcludedType2 = Exclude<string, number> // string
type ExcludedType3 = Exclude<string | number | boolean, string | boolean> // number
```

# Extract`<T,U>`

`Extract<T,U>`は`Exclude<T,U>`とは反対で`T`型のプロパティで`U`型に代入可能なプロパティのみを残した型を構築します。
下記の例では、
`ExtractedType`では"`id" | "name"`から`"id" | "address"`に代入可能な`"id"`のみ残した型を構築します。
`ExtractedType2`では代入可能な型は存在しない無いので、`never`となります。
`ExtractedType3`では`string | number | boolean`で`string | boolean`が代入可能なので`string | boolean`となります。

```ts
interface TypeA {
  id: number
  name: string
}
interface TypeB {
  id: number
  address: string
}

type ExtractedType = Extract<keyof TypeA, keyof TypeB> // "id"
type ExtractedType2 = Extract<string, number> // never
type ExtractedType3 = Extract<string | number | boolean, string | boolean> // string | boolean
```

# NonNullable`<T>`

`NonNullable<T>`は`T`から`null`と`undefined`を取り除いた型を構築します。
下記の例では、
`TypeA`は`string | number | undefined`から`undefined`を取り除いた, `string | number`になります。
`TypeB`は`string[] | null | undefined`から`null | undefined`を取り除いた, `string[]`になります。

```ts
type TypeA = NonNullable<string | number | undefined> // string | number
type TypeB = NonNullable<string[] | null | undefined> // string[]
```

# Parameters`<T>`

`Parameters<T>`は関数型`T`の引数の型をタプル型として抽出した型を構築します。

```ts
const func = (text: string, num: number) => {
  return `${text}${num}`
}

type TypeA = Parameters<typeof func> // [string, number]
```

# ConstructorParameters`<T>`

`ConstructorParameters<T> `は`T`型のコンストラクタの引数の型をタプルとして抽出した型を構築します。

```ts
class Person {
  name: string
  age: number
  constructor(name: string, age: number) {
    this.name = name
    this.age = age
  }
}
type TypeA = ConstructorParameters<typeof Person> // [string, number]
```

# ReturnType`<T>`
`ReturnType<T>`は関数型`T`の戻り値の型を返します。
下記では`func2`の戻り値の型は`number`なので、`TypeA`は`number`となります。

```ts
const func2 = (): number => 1
type TypeA = ReturnType<typeof func2> // number
```

# ThisParameterType

関数型`T`の`this`引数の型を抽出した型を構築します。
__`--strictFunctionTypes`が設定されている時のみ、期待通りの動きをします。詳細は[こちら](https://github.com/microsoft/TypeScript/issues/32964)。__

```ts
function toHex(this: Number) {
  return this.toString(16)
}
type TypeA = ThisParameterType<typeof toHex> //Number
```

# OmitThisParameter

関数型`T`の`this`引数の型を取り除いた型を構築します。
下記の例では`TypeA`は`toHex`から`this`引数を除いた関数型`()=> string`を返します。
__`--strictFunctionTypes`が設定されている時のみ、期待通りの動きをします。詳細は[こちら](https://github.com/microsoft/TypeScript/issues/32964)。__

```ts
function toHex(this: Number) {
  return this.toString(16)
}
type TypeA = OmitThisParameter<typeof toHex> // () => string
```

# ThisType`<T>`
`ThisType<T>`を使用する事で、関数の中で参照される`this`の型を`T`とてコントロールする事ができます。
__`-noImplicitThis`がが設定されている必要があります。__

```ts
interface User {
  name: string
}

interface Greetings {
  hello(): void
}

const user: Greetings & ThisType<User> = {
  hello() {
    console.log(`${this.name}です。`)
  },
}
user.hello()
```

詳しくはstackoverflowの[What is TypeScript's ThisType used for?](https://stackoverflow.com/questions/55029032/what-is-typescripts-thistype-used-for)でわかりやすく説明されていました。

# 参照
- [Utility Types · TypeScript](https://www.typescriptlang.org/docs/handbook/utility-types.html)