TypeScriptでよく使う関数などをまとめてみた

## extends keyof

オブジェクト(配列)のkey達を取得する

```tsx
export interface FormValues {
  last_name: string | null;
  first_name: string | null;
  gender: number | null;
  birthday: string | null;
}
const event = <K extends keyof FormValues>(
val: FormValues[K] // FormValuesの中のいずれかのプロパティ,
key: K, // last_name | first_name | gender | birthday
) => {
FormValues[key] = val; // オブジェクトの中の1つのプロパティに代入する
}
```

## 継承

interfaceやtypeを追加で定義する

```tsx
interface Object {
  name: string;
  height: number;
}

interface newObject extends Object {
  birthday: string;
}

const data:newObject  = 
{
  name: '澁谷かのん',
  height: 159,
  birthday: '05/01',
}
```

## 合併型(Union Types)と交差型(Intersection Types)

合併型はorを表す型で、交差型は&を表す型

```tsx
type Kick = {
  effect: boolean,
  hit: boolean,
};

type Punch = {
  hit: boolean,
  damage: number,
};

type KickOrPunch = Kick | Punch;
type KickAndPunch = Kick & Punch;

// 合併型なので、Kick, Punch型両方のプロパティが使える
const SuperAtack: KickOrPunch = {
  effect: true,
  hit: true,
  damage: 10,
};

// 合併型なため、どちらかの型ということを表せれば良い
const normalAtack: KickOrPunch = {
  hit: false,
  damage: 3,
};

// 合併型とはいえどちらかの型を満たせなけれNG
const errorAtack: KickOrPunch = {
  effect: false,
  damage: 3,
};
// Type '{ effect: false; damage: number; }' is not assignable to type 'KickOrPunch'.
//   Property 'hit' is missing in type '{ effect: false; damage: number; }' but required in type 'Punch'.

// 交差型なので、合併型同様Kick, Punch型両方のプロパティが使える
const doubleAtack: KickAndPunch = {
  effect: true,
  hit: true,
  damage: 10,
};

// 交差型は集合元の型全てのプロパティを使わなくてはならない
const errorAtack2: KickAndPunch = {
  hit: true,
  damage: 3,
};
// Type '{ hit: true; damage: number; }' is not assignable to type 'KickAndPunch'.
//   Property 'effect' is missing in type '{ hit: true; damage: number; }' but required in type 'Kick'.
```

## interfaceとtypeの違い

1.interfaceではオブジェクトとクラスの型だけ定義できるが、typeでは他の型も参照できる

2.interfaceは拡張ができるが、typeはできない(スコープ内で重複できない)

```tsx
interface User {
  name: string;
}

interface User {
  level: number;
}

const user: User = {
  name: "apple",
  level: 0
};

------------------------------------------------------

type User = {
  name: string;
} //Duplicate identifier 'User'

type User = {
  level: number;
} //Duplicate identifier 'User'
```

3.typeのみ三項演算子が使える

```tsx
type User<T extends boolean> = T extends true ? number : string

const truthyValue: User<true> = 156;
const falsyValue: User<false> = '愛本輪怐';
```

4.typeは数も同じでなければならない(タプル)

```tsx
interface A {
    0: number;
    1: string;
    2: number;
}

type B = [number, string, number];

// ok
const a: A = [0, '1', 2, 3];

const b: B = [0, '1', 2, 3]
// Type '[number, string, number, number]' is not assignable to type 'B'.
//   Types of property 'length' are incompatible.
//     Type '4' is not assignable to type '3'.
```

参考

[https://zenn.dev/luvmini511/articles/6c6f69481c2d17](https://zenn.dev/luvmini511/articles/6c6f69481c2d17)

[https://nju33.com/notes/typescript/articles/Interface と Type の比較#三項演算子](https://nju33.com/notes/typescript/articles/Interface%20%E3%81%A8%20Type%20%E3%81%AE%E6%AF%94%E8%BC%83#%E4%B8%89%E9%A0%85%E6%BC%94%E7%AE%97%E5%AD%90)[https://qiita.com/tkrkt/items/d01b96363e58a7df830e](https://qiita.com/tkrkt/items/d01b96363e58a7df830e)

## Mapped Types

指定した型を変換して新しい型を生成する機能

[解説はこちら](https://www.typescriptlang.org/ja/play?ssl=1&ssc=15&pln=1&pc=4&q=281#code/PTAEFsEMAdoUwCagC4E96HsGQa3KDsGQ0eqBJDIMKKg1gyANpoOoMgIgyGA68oNEMgnaaCrNoOYMgQgyBRDIIAMAsAFAhQgTqVA4c6AQtxKBITUDbxq0CyDPTytAmgyAgBgEChUWIhTo4OQBEMgeQZ29QP7yVRhi1hAR6aANbXw5AFwmAwJUBjaYAgVAoEcjQDEGQGUGQAsGVQ1BMEBo+UAJBkAHBm4AQQAFAElAGQZAU7lAaDkcRIAnZABLAGdkAkAV+JUQikA-BhUALk1+IoA7ZDh8gDNIAGM4UAListAAbwFQUCKEBtBWgFdwACNOgG4JuchwOFmy-LaAc3X+SaWigHtd5H3Wo4EAX2ahQCCGCiTC0uQcQAA5VxwpQAvZip6ClUgRAFgJFEAZgx2UAAsgEQCACYBD+QogH0GKgheR8SKgb6AGiDJBgyGiSDl8ARaIAEI2BgFH9QCBkelzKwKIBwhgCTX4AjaHW6fQGQ0+ADFzvkAKIIIrIMYbaazBbLNYbVpbOAAfiuNzuJ1AZ3OGtAe0Ox0eXNxQXw6UAUHKADCi8h8yngQoAYFUA+OaAVQZADEMgCsGEzewDGDFC6gFYYB75UAvwGAcgMMIA9dMAHHokQAbWVQWeyItoYPAkGhME4KbJ0XQqQp6hEBDmBgBZVDJSAfSAAGwAKgYADwt+AAPlAAF4ZTqhB24CRANQqtU99BUgE8GKE4QDrDIBbhkAiwyAMYZAMUMBA2Qg13sAJArSGR1FQbADayXy53ghVQU1aoAA1nBUOcuqAhwBdA1Ds8Xq9od8mscsLAiE3CUCYPKdD0-QEIAF76eIWlI0vQgDHcoA8QycCQOIZro2YGAQFiABSuJbqOWBigJWmaIIKZQiuKkrSn21a1vWzZtjRyCdkB5qeqwgDeDCEgDJDIAlgyADHagDlLqo6TYWAQSehg3CADTmgCm5oAXm6APiuFDelQ3DTOkCwNg2JDevQS6AP0MgA-DIAzwwEIAjFGAJ3a0J1FQpawoAJXKAHe6hAWIG3CAIYMrL+iEgCcpoAIarQoA-gy1GyATpmAAAUgDOURQJgYKAcAAB5bNADY7PMrQXK0AC0kCtAgRWQfkJRwL0xTnMVFYlKABCAEPKgDmjgAlM0FYUTWdbFI2Q50RKUrtgY3Z9uMOo-penRoLeD5Pi+b4GJ+szfues3XgBDygAAZGMUwzHMiwrPkoD3NxQi2hgOhZvo8A4IACr6ADnmBG+bCckhHpgAOpruOA+AQgCAxoAJgyAFUMgBrDIAHQyAOUMgD1DIAEwwhIAewwWVDR5xaAIHcHgOCALRyJB6Y4gAU6tCVD0KEBCAOz6gBsSsCeDpGIkgkWW-A9QAwqK+Q1cglG4Rxw0Mb2vUsQNbHwILo0cVxTxgJkVq3VReHwOkwnGAEJCAKtKtDAoA0gw4CEULPIAhD6ABrK3pRCyaLSbCgBf6oAcJ7iN62s4AJIkEIA1QyAAsMFlk65uKvNw7qAJEMJCAI+2JiAKfunAYoALBreApAAWpUIEs5znPerVtSYgAGDO6VCciAsKJ8gyDQCUDQgAA7jXAB0jW9Ps0DIA2pUHLXooHMACDnL0JTAMnZVpxnwCQAgABupX9OVjW1yX4ANgAxHdiBFY1AhAA)

[使用例](https://soarflat777.hatenablog.com/entry/2019/07/05/151951)

[ネストされた場合](https://tech-1natsu.hatenablog.com/entry/2018/07/07/233655)

リテラル型とプリミティブ型

プリミティブ型は`number, string, null, undefined`などのこと。

リテラル型とはプリミティブ型の特定の値だけを許容する型

```tsx
const impossible: false = false;
const three: 3 = 3;
const radetzky: 'Radetzky' = 'Radetzky';
```

## 型アサーション（as）

型定義の上書き機能。型アサーションを使えば、任意のタイミングで型を上書きできちゃうため型安全性が全く保証されないので注意

```tsx
type Foo = {
    bar: number;
    bas: string;
}

const foo = {} as Foo;
foo.bar = 123;
foo.bas = 'hello';
```

## unknownとanyの違い

unknown型に代入したオブジェクトのプロパティ、メソッドは型ガードや型アサーションを経由しないと使用(実行)できない。

```tsx
const unknown1: unknown = 0.8;
const unknown2: unknown = 'Comment allez-vous';
const unknown3: unknown = {
  x: 0,
  y: 1,
  name: 'origin'
};

console.log(unknown1.toFixed());
// Object is of type 'unknown'.
console.log(unknown2.length);
// Object is of type 'unknown'.
console.log(unknown3.name);
// Object is of type 'unknown'.
```

anyと違い、型ガードはしっかりされる

```tsx
function toString(n: unknown): string {
  switch (typeof n) {
    case 'object':
      if (n === null) {
        return  n.substr(1);
        // Object is possibly 'null'.
      }
      return  n.substr(1);
      // Property 'substr' does not exist on type 'object'
    case 'string':
      return  n.substr(1);
    default:
      return  n.substr(1);
     // Object is of type 'unknown'.
  }
}
```

## Partial<T>

すべてのプロパティにOptional(任意)であることを意味する?を適用します。

```tsx
interface User {
  name?: string,
  height?: string,
  age?: number,
}

function findUsers(
  name?: string,
  height?: string,
  age?: number,
): void {
  console.log(age);
}
// OKだけど引数の分だけundefined入れるのはだるい・・・
findUsers(undefined, undefined, 22);
```

```tsx
interface User {
  name?: string,
  height?: string,
  age?: number,
}

type FindUsersArgs = Partial<User>;

function findUsers({ name, height, age }: FindUsersArgs): 
 void {
  console.log(age);
}

// 引数1つでOK!
findUsers({ age : 22 });
```

## Required<T>

すべてのプロパティからOptionalであることを意味する?を取り除く

```tsx
interface User {
  name?: string,
  height?: string,
  age?: number,
}

type FindUsersArgs = Required<User>;

function findUsers({ name, height, age }: FindUsersArgs): 
 void {
  console.log(age);
}

findUsers({ age : 22 });
// Argument of type '{ age: number; }' is not assignable to parameter of type 'Required<User>'.Type '{ age: number; }' is missing the following properties from type 'Required<User>': name, height
```

## Record<K, T>

以下の書式を持つ組み込み型で、Kに指定したキーに対して、型Tを設定してくれるものです。

```tsx
// Record<K extends string | number | symbol, T> Kに指定された型をキーにして,それぞれに対して、型Tを設定する。
type User = {
  address: string;
  name: String;
};

const Users:Record<number , User> = {
  1 : {
    address: "Shinjuku",
    name: "user1"
  },
  2 : {
    address: "Shibuya",
    name: "user2"
  },
  'idol':{
    address: "Nakano",
    name: "user3"
  },
// Type '{ 1: { address: string; name: string; }; 2: { address: string; name: string; }; idol: { address: string; name: string; }; }' is not assignable to type 'Record<number, User>'.Object literal may only specify known properties, and ''idol'' does not exist in type 'Record<number, User>'.
};
```

## Pick<T, K>

既に存在するT型の中からKで選択した一部のプロパティのみを含んだ新たな型を構築します。

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

const preview: TodoPreview = {
  title: '部屋の掃除',
  completed: false,
}

console.log(preview)
```

## Omit<T,K>

Omit<T,K>は既に存在するT型の中からKで選択した一部のプロパティを除いた新たな型を構築します。

```tsx
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 }

// export interface MaintenanceConfirmData
//   extends Omit<MaintenanceRequestData, 'old_inputs'> {
//   inputs: MaintenanceRequestForm;
// }
```

## Exclude<T, U>

ユニオン型TからUを取り除きます。

```tsx
type Grade = 'A' | 'B' | 'C' | 'D' | 'E';
// A~DがOK
type PassGrade = Exclude<Grade, 'E'>;
```

## Extract<T, U>

Excludeと逆です。ユニオン型TからUを抽出します。

```tsx
type Grade = 'A' | 'B' | 'C' | 'D' | 'E';
// EのみOK
type FailGrade = Extract<Grade, 'E'>;
```

## タプル

複数の値を保持することのできる型です。 [] 記号を使うところも配列によく似ていますが、それぞれの位置の要素の型を明示しておくことができます。

```tsx
let vote: [string,number]
vote = ['red', 100];// OK
vote = ['green', 200];// OK
vote = ['yellow', 300];// OK
vote = ['AAA', 'BBB'];// Error
```

参考: [https://maku.blog/p/6uzqf4q/](https://maku.blog/p/6uzqf4q/)

ユニオン型 (Union Types)

[こちら](https://book.yyts.org/features/union-types)

## ReturnType

関数の返り値を型に変換する

```tsx
const foo = ()=> {
  return {
    foo: 1,
    fooo: 2,
    foooo: 3
  }
}

type Foo = ReturnType<typeof foo>

/* type Foo = {
	foo: 1,
	fooo: 2,
	foooo: 3
}
*/
```