TypeScript 型 メモ

## 型リテラル
### `[]`
- 空のTupleを表す
- `Params<T>`は関数の引数がないときに引数の型は`[]`になる

### any
- すべての型の値を代入することができる
- あらゆるプロパティがあるものとしてアクセスすることができる
- すなわち型システムとしてこいつは崩壊しているので使用するべきではない

```typescript
const notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn’t check)
```

### unknown
- 他の言語で言うany

[TypeScript 3.0のunknown型 - タイプセーフなany - Qiita](https://qiita.com/suzuki_sh/items/9b168b44d1d21c127aeb)

### void
- 他の言語で言う普通のvoid、関数が何も返さないときの値
- 一応`null`と`undefined`スーパータイプになれる

```typescript
let unusable: void = undefined;
unusable = null; // OK if `—strictNullChecks` is not given
```

### never
- bottom型と呼ばれる値を持たない型
- 決して処理が終わらないものを表すときに使用する i.e. `while(truc)`、例外のthrow
- 集合論における空集合のようなものなので、あらゆる型に代入できるがnever以外を代入できない

```typescript
const a: never = 1 // compile error
const b: number = never // ok
```

#### never型とのunion type
- neverと他の型のunion typeはneverが消える

```typescript
number | never == number
```

## 型コンストラクタ
### `Required<T>`
* Tの内nullableな属性の方を全てマストにする

### `Parameters<T>`
- Tが関数ならばその引数の型を返す
- そうでないならneverを返す

### `Exclude<T, U>`
- TがUのサブタイプならneverを返し、そうでないならTを返す
- union distributionと組み合わせることでunionから不要な物を削除できる

```typescript
type A = "a" | "b"
type B = "b"

Exclude<A, B>
// => "a"
```

### `Pick<T, K extends keyof T>`
- Tからunion typeであるKに含まれるkeyの値だけを取り出す

```typescript
type A = {a: any, b: any}
Pick<A, "a">
// => {a: any}
```

### `Omit<T, K extends keyof any>`
- TからKをのぞいた型を返す

## 型演算子
### keyof T
- Tのプロパティのキーからなるunion typeを返す

```typescript
type T = {a: any; b: any}
keyof T
// => "a" | "b"
```

### in 
- mapped typeと呼ばれる機能を実現するためのもの
- 配列の型の一つ一つを処理して新たな型を返すようなときに使用する

```typescript
type Readonly<T> = {
    readonly [P in keyof T]: T[P]; // Tのキー全てにreadonly属性をつけた新たな型を定義している
};
```

[TypeScript2.1.4 で導入された `keyof` キーワードと `in` キーワード、そして Lookup Types と Mapped Types - 角待ちは対空](https://blog.yux3.net/entry/2017/02/08/033834)

### extends
#### 型の境界
- ある型が他の型のサブタイプであることを指定する場合に使用する

```typescript
const apply<T extends (...args: any[]) => any, A extends any[]>(f: T, args: A) => f(...args)

apply((...args: number[]) => args.length, [1, 2])
// => 2
```

#### conditional type
- ある型が別の型のサブタイプかどうかで型を分岐させる

```typescript
declare function f<T extends boolean>(x: T): T extends true ? string : number;

// Type is 'string | number'
let x = f(Math.random() < 0.5);
```

[TypeScript: Handbook - Advanced Types](https://www.typescriptlang.org/docs/handbook/advanced-types.html#conditional-types)

- 更に`infer`を使用することで型変数を定義し、それを用いて返す型を定義することができる

```typescript
// Rを型変数として定義し、条件にあうときはそのRを用いて型を返す
// inferがなければRはそもそも定義されていない型変数なので使用できない
type ReturnType<T> = T extends (…args: any[]) => infer R ? R : any;
```

#### union typeのサブタイプとextend判定
- union typeのサブタイプはその候補を減らした型が当てはまる

```typescript
type T = "a" | "b"
“a” extends T // => true
“b” extends T // => false
```

- union typeの候補数を増やしても同様

#### union distribution
- 上記のunion typeにおけるサブタイプとスーパータイプの関係性を保証するのがunion distributionという仕組み
- 簡単に言うとunion typeの対するextends判定は分配法則に従って実行される

```typescript
type A = number[] | string
type ArrayValue<T> = T extends (infer U)[] ? U : undefined
ArrayValue<A> // => number | undefined
```

## ユースケース
### スマートキャストするための型判定関数の作成
`is`を使用する

```typescript
const isString = (arg: any): arg is string  => typeof arg === "string";

const foo = 'foo' as any // ここではanyとして振る舞いたい

if (isString(foo)) {
  // isStringの結果、arg is string = foo is string = fooはstring型であることが確定している
    foo.length // fooをas anyしたけどfooはstringとして解釈される
}
```

[Advanced Types · TypeScript](https://www.typescriptlang.org/docs/handbook/advanced-types.html#type-guards-and-differentiating-types)

### nullableをnon nullにキャストする
`!`(Non-null assertion operator)を使用する

```typescript
const a: string? = ""
const b: string = a // compile error
const c: string = a! // success
```