[Typescript] 応用


#インターセクション型
A & Bのような型のことを言います。

↓EngineerとBloggerオブジェクトの全てを入れる必要があります。
↓被っているものは１つで良いとみなされるので、nameも１つで大丈夫です。

```.ts 
type Engineer = {
  name: string;
  role: string;
}

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

type EngineerBlogger = Engineer & Blogger;

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

↓だったら、type Mixはnumber型になります。
↓NumberBooleanとStringNumberで重複しているのがnumberのみだからです。

```.ts
type NumberBoolean = number | boolean;
type StringNumber = string | number;
type Mix = NumberBoolean & StringNumber;
```

#Type guard
条件分を使って、型を絞り込んでいく方法です。

**typeof**

```.ts
function toUpperCase(x: string | number) {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return '';
}
```

**in演算子**

↓nomadWorkerというオブジェクトにroleキーは存在しますか？という意味になります。
↓存在すればtrueを返します。

```.ts
function describeProfile(nomadWorker: NomadWorker) {
  console.log(nomadWorker.name);

  if ('role' in nomadWorker) {
    console.log(nomadWorker.role);
  }
}
```

**instanceof**
classの場合使えます。

↓if (pet instanceof Bird)は、「petはBirdのインスタンスですか？」と言っています。
↓Birdクラスから設計されたインスタンスだった場合にtrueを返します。

```.ts
class Dog {
  speak() {
    console.log('bow-wow');
  }
}
class Bird {
  speak() {
    console.log('tweet-tweet');
  }
  fly() {
    console.log('flutter');
  }
}

type Pet = Dog | Bird;
function havepet(pet: Pet) {
  pet.speak();
  if (pet instanceof Bird) {
    pet.fly();
  }
}
```

#Tagged union
Type guardのように型を絞り込んでいく、Tagged unionデザインパターンです。

↓DogにもBirdにもkindを置いて、switchに指定して、caseで判別するといった方法です。

```.ts
class Dog {
  kind: 'dog' = 'dog'
  speak() {
    console.log('bow-wow');
  }
}
class Bird {
  kind: 'bird' = 'bird'
  speak() {
    console.log('tweet-tweet');
  }
  fly() {
    console.log('flutter');
  }
}

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

#Type assertion
手動で型を上書きする方法です。
↓２つとも意味は同じです。
↓document.getElementById('input')を、手動で無理やり「HTMLInputElementです！」と
↓Typescriptに教えてあげています。
↓そうしないとinputがHTMLInputElementかnullかが分からないからです。

```.ts
const input = <HTMLInputElement>document.getElementById('input');
```

```.ts
const input = document.getElementById('input') as HTMLInputElement;
```

#Non-null assertion operator

↓末尾についている ! は、絶対にnullじゃないと言い切るものです。

```.ts
const input = document.getElementById('input')!;
```

#Index signature

オブジェクトの中身を追加できるというものです。

↓通常オブジェクトに中身を追加できなくて、エラーが起きます。
[![Image from Gyazo](https://i.gyazo.com/8f5059a564dec0f119944a0f147ae30f.png)](https://gyazo.com/8f5059a564dec0f119944a0f147ae30f)

↓[index: string]: string;という一文を付け加えると、全てOKになります。
↓ただし、[index: string]: string;の最後の型がstringだったら、
↓他のメンバーも全てstring型にしないといけません。（例えばageなど）
[![Image from Gyazo](https://i.gyazo.com/0261fb4e7ccecdea6099fa0a8efc4d65.png)](https://gyazo.com/0261fb4e7ccecdea6099fa0a8efc4d65)

↓[index: number]: string;とすると、キーが数値でないとダメになります。
[![Image from Gyazo](https://i.gyazo.com/8f664ab8f2df3fc61fdaf2568a246131.png)](https://gyazo.com/8f664ab8f2df3fc61fdaf2568a246131)

#関数のオーバーロード
関数の戻り値を、正しくTypescriptに伝える方法です。

↓最後の行のupperHelloは、明らかにstringのはずなのにstring | numberと認識されています。
↓Typescriptには分からないのです。

```.ts
function toUpperCase(x: string | number):string | number {
  if (typeof x === 'string') {
    return x.toUpperCase();
  }
  return x;
}

const upperHello = toUpperCase('Hello');

```

↓ここで関数のオーバーロードを使います。
↓function toUpperCase(x: string): string;　　　＝　 stringの返り値はstringだよー
↓function toUpperCase(x: number): number;　 ＝ 　numberの返り値はnumberだよー
↓としてあげることで解決します。

```.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');
```

これがオーバーロードです。

#Optional Chaining

Javascriptは、要はundefinedかnullの
メソッドやプロパティに対してアクセスしようとするとエラーが出ます。

そのエラーを防ぐために何かあったらundefinedで止めておくといった書き方です。

```.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

const downloadedData: DownloadedData = {
  id: 1
}

console.log(downloadedData.user?.name?.first);
```

↑downloadedData.user?.nameは、
↑downloadedData.userがundefinedもしくはnullだったら、undefinedを返す、
↑それ以外が入っていたら、nameを返すという意味です。

#Nullish Coalescing
↓undefinedとnullの２つだけに対しては'no-user'になるといったようなものを
↓Nullish Coalescingと言います。

```.ts
const userData = downloadedData.user ?? 'no-user';
```

#LookUp型
オブジェクトの型の、メンバーが持っている型にアクセスするときに使います。

↓[　]で指定すると、そのメンバーの型にアクセスできます。
↓type idはnumber型になっています。

```.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

type id = DownloadedData['id'];
```

↓type idは（number　|　user?）型になっています。

```.ts
interface DownloadedData {
  id: number;
  user?: {
    name?: {
      first: string;
      last: string;
    }
  };
}

type id = DownloadedData['id' | 'user'];
```

#Typescriptの加算演算表
「Typescriptの型安全性」と「Javascriptの柔軟性」

        |Any　　|Boolean　|Number |String  |Other
--------|---------|-------|------|--------|------------
Any　　  |  Any    | Any   | Any	 | String  | Any
Boolean | Any	  |       |      | String  |  	
Number  | Any	  |       |Number| String  |
String	| String  | String|String| String  |String
Other	| Any	  |       |      | String  |

#オーバーロードを型で表現する

↓オーバーロードを型で表現する場合は、
↓オーバーロードした全ての関数に対応した関数しか入れれません。

```.ts
interface TmpFunc {
  (x: string): number;
  (x: number): number;
}
const upperHello: TmpFunc = function(x: string | number) { return 0 };
//string と numberに対応した型の関数しか使えない
```

#関数型のIntersection

```.ts
interface FuncA {
  (a: number, b: string): number;
  (a: string, b: number): number;
}

interface FuncB {
  (a: string): number;
}

let intersectionFunc: FuncA & FuncB;
```

↑intersectionFunc: FuncA & FuncB;は、
↓のようにオーバーロードされた型になっています。

```.ts
  (a: number, b: string): number;
  (a: string, b: number): number;
  (a: string): number;
```


#関数型のUnion型
↓unionFuncは、パラメーターはintersection型になり、戻り値はunion型になります。

```.ts
interface FuncA {
  (a: number): number;
}

interface FuncB {
  (a: string): string;
}

let unionFunc: FuncA | FuncB;
```

#Rest Parameter
↓関数advanceFnに、いくつも引数を入れられるよーというものです。
↓.を３つ付けてその後名前を付けます。
↓するとその名前が配列としてadvanceFn使えます。
↓さらに: number[　]のように、配列の型を付けることでRest Parameterに型付けできます。

```.ts
function advanceFn(...args: number[]) {
  args[0];
}
advanceFn(0, 1, 2, 3)
```

↓Tuple型もつけられます。
↓Optional parameterも付けれます。
↓可変調ではなくなります。

```.ts
function advanceFn(...args: [number, string, boolean?]) {
}
advanceFn(0, 'web', true);
```

↓Tuple型に可変長を付けることもできます。
↓... ＋　型　＋　配列

```.ts
function advanceFn(...args: [number, string, boolean, ...number[]]) {
  args[0];
}
advanceFn(0, 'web', true, 0, 1, 2, 3);
```

#配列とTupleにreadonly修飾子を付ける

↓:と配列の間、型のところにreadonlyを付けることができます。

```.ts
function advanceFn(...args: readonly [number, string, boolean, ...number[]]) {
}
advanceFn(0, 'web', true, 0, 1, 2, 3);
```

読み物になるので、args.pushで入れれなくなったりします。

#const Assertion
as constと付けると、定数のようになります。

↓milkはstring型です。

```.ts
let milk = 'milk';
```

↓milkはmilkというString literal型になります。

```.ts
let milk = 'milk' as const;
```

↓arrayはnumber[　]になります。

```.ts
const array = [10, 20];
```

↓readonly [10, 20]という、　readonly　＋　Tuple型になります。

```.ts
const array = [10, 20] as const;
```

↓はconst peter: {
　　　name: string;
　　　age: number;
　　}
↓となります。

```.ts
const peter = {
  name: 'peter',
  age: 38
}
```

↓はconst peter: {
　　　readonly name: "peter";
　　　readonly age: 38;
　　}
↓となります。

```.ts
const peter = {
  name: 'peter',
  age: 38
} as const;
```

#型の中でtypeofを使う
↓peterの型を代入したいとき、これではダメです。
↓peterは値なので、PeterTypeは成り立ちません。

```.ts
const peter = {
  name: 'peter',
  age: 38
} as const;

type PeterType = peter;
```

↓そんなときpeterの型を取得するにはtypeofをくっ付けます。

```.ts
const peter = {
  name: 'peter',
  age: 38
} as const;

type PeterType = typeof peter;
```