TypeScriptの応用的な使い方まとめ

## インターセクション型
複数の型を持つ型を定義する際にインターセクション型を定義する。
```ts
type Engineer = {
    name: string,
    role: string
}

type Blogger = {
    name: string,
    follower: number
}

type ENginnerBlogger = Engineer & Blogger;

const quill: ENginnerBlogger = {
    name: 'Quill',
    role: 'front-end',
    follower: 1000
}
```
インターフェースで定義することもできる。
```ts
interface Engineer {
    name: string,
    role: string
}

interface Blogger {
    name: string,
    follower: number
}

interface ENginnerBlogger extends Engineer, Blogger {}

const quill: ENginnerBlogger = {
    name: 'Quill',
    role: 'front-end',
    follower: 1000
}
```

## 条件を指定し型を絞り込む
型を判定
```ts
function toUpperCase(x: string | number) {
    if (typeof x === 'string') {
        return x.toUpperCase();
    }
    return '';
}
```
プロパティがあるか判定
```ts
type NomadWorker = Engineer | Blogger;
function describeProfile(nomadWorker: NomadWorker) {
    console.log(nomadWorker.name);
    if('role' in nomadWorker) {
        console.log(nomadWorker.role);
    }
}
```
どのクラスのインスタンスか判定
```ts
type Pet = Dog | Bird;
function havePet(pet: Pet) {
    pet.speak();
    if (pet instanceof Bird) {
        pet.fly();
    }
}
havePet(new Bird())
```

## タグ付きユニオン
```ts
class Dog {
    kind: 'dog' = 'dog'
    speak() {
        console.log('bow-wow');
    }
}
class Bird {
    kind: 'bird' = 'bird'
    speak() {
        console.log('tweet');
    }
    fly() {
        console.log('flutter');
    }
}

type Pet = Dog | Bird;
function havePet(pet: Pet) {
    pet.speak();
    switch (pet.kind) {
        case 'bird':
            pet.fly();
    }
    if (pet instanceof Bird) {
        pet.fly();
    }
}
havePet(new Bird())
```

## 型アサーション
```ts
const input = document.getElementById('input');
// NG
input.value = 'initial input value';
```
getElementById()で取得するとHTMLElementという型で取得できるが、これはvalueプロパティを持っていない。
よってgetElementById()で取得した要素をinputとして扱うようにHTMLInputElement型で上書きしてやる必要がある。

```ts
const input = <HTMLInputElement>document.getElementById('input');
input.value = 'initial input value';
```
もしくは下のようにasで定義することもできる。
```ts
const input = document.getElementById('input') as HTMLInputElement;
input.value = 'initial input value';
```

## Non-null assertion operator
エクスクラメーションマークをつけることでnullでないことを明確にすることができる。
以下の場合、getElementById()で要素を取得するとHTMLElementかnullのユニオン型だが、
エクスクラメーションマークを付けることでHTMLElementのみを定義することができる。
```ts
const input = document.getElementById('input')!;
```

## インデックスシグネチャ
通常、以下のようにdesignerオブジェクトにroleプロパティを追加することはできない。
```ts
interface Designer {
    name: string;
}
const designer: Designer = {
    name: 'Quill',
    // 追加できない
    role: 'web'
}
```
追加するために以下のようにインデックスシグネチャを利用する。
```ts
nterface Designer {
    name: string;
    [index: string]: string;
}
const designer: Designer = {
    name: 'Quill',
    role: 'web'
}
```
インデックスシグネチャで定義した型以外は追加できないことに注意。
以下のようにnumber型を追加することはできない。
```ts
interface Designer {
    name: string;
    [index: string]: string;
}
const designer: Designer = {
    name: 'Quill',
    role: 'web',
    // 追加できる
    food: 'apple',
    // 追加できない
    number: 2
}
```

## 関数のオーバーロード
引数にunion型を取る関数の実行結果を、変数upperHelloに代入する場合、
toUpperCase()の引数を文字列にした場合でもupperHelloはunion型となってしまう。
toUppercase()の返り値によって代入する変数の型も合わせたい。
```ts
function toUpperCase(x: string | number) {
    if (typeof x === 'string') {
        return x.toUpperCase();
    }
    return x;
}
const upperHello = toUpperCase('hello');
```
その場合は関数のオーバーロードを実行する。
```ts
function toUpperCase(x: string): string;
function toUpperCase(x: number): number;
function toUpperCase(x: string | number): string | number {
    if (typeof x === 'string') {
        return x.toUpperCase();
    }
    return x;
}
const upperHello = toUpperCase('hello');
const upperHello2 = toUpperCase(2);
```
upperHelloはstring、upperHello2はnumberとなる。

## Optional Chaining
user?のように定義した場合、「またはundefined」という条件を加えることができる。
その際undefinedのプロパティを出力しようとするとエラーとなってしまうが、
undefinedを出力したい場合、出力したいプロパティの後ろに?をつけることでエラーではなくundefinedを出力することができる。
```ts
interface DownloadedData {
    id: number;
    user?: {
        name?: {
            first: string;
            last: string;
        }
    }
}
const downloadedData: DownloadedData = {
    id:1
}
// エラー
console.log(downloadedData.user.name);
// undefined
console.log(downloadedData.user?.name);
```

## Nullish Coalescing
PHPのNull合体演算子っぽいやつ
「NullもしくはUndefinedだったらこれ」という条件をつけることができる。
```ts
const userData = downloadedData.user ?? 'no-user';
```

## LookUp型
オブジェクトの型にアクセスする。
```ts
type id = DownloadedData["id"];
type id2 = DownloadedData["user"]["name"];
```

## レスとパラメータに配列やタプルを指定する
readonlyもつけられる
```ts
function advancesFn(...args: readonly[number, string, boolean?, ...number[]]) {
    
}
advancesFn(0, 'hi', true, 1, 1, 3);
```

## typeofで型を取得
```ts
const peter = {
    name: 'Peter',
    age: 38
} as const;
type PeterType = typeof peter;
```