TypeScript入門者がハマりがちな記法(文法)の呼び方と簡易解説まとめ

この記事は、かつてTypeScriptで見かける記法が何と呼ぶのかすら分からず困っていた頃の自分へ向けて送るものですが、現在TypeScriptへ入門中の方々にも役立つかなと思い公開する次第です。正確な内容に関してはぜひ[公式](https://www.typescriptlang.org)をご覧ください。

内容の修正や項目の追加などは随時承ります。

Type Annotation
--
### こんな奴
```ts:型注釈.例.ts
let foo: number

foo = 777 // OK
foo = 'hoge' // コンパイルエラー
```
### 日本語での呼び名
- 型注釈
- 型アノテーション

### ふわっと紹介
値を初めて定義する際によく使われます。
値に初期値が存在する場合は型推論が働き、`let foo = 777`のような宣言でも`foo`の型が`number型`であることをコンパイラが推定してくれます。初期値の無い宣言で使われることがほとんどですが、_代入時の推論には無理がある場合_などでもちょこちょこ使います。

### 参考文献
- https://www.typescriptlang.org/docs/handbook/basic-types.html - TypeScript公式

---

Type Assertion
--
### こんな奴
```ts:型注釈.こんな奴.ts
const foo = <Bar> bar // <Type> value

const foo = bar as Bar // value as Type
```
- `<Type> value`もしくは`value as Type`という、式として等価な2通りの記法が存在します。
- **可能ならば_`value as Type`での記述_が推奨されます**
- **_`<Type> Value`での記述_はJSX構文と衝突するためTSXファイルで使用できません**

### 日本語での呼び名
- 型アサーション

### ふわっと紹介
`型アサーション`は値の持つ型情報を_**実行時の値とは別に**上書きします_。
_実際の**値の型とアサーションの型が確実に一致**するとき_以外は使用すべきでありません。

### コード付き解説
```ts:型アサーション.基本構文.ts
const element: HTMLElement

// 代入される型を**無視して**`bar`の型が`number型`_となります。
const foo = inputElement as HTMLInputElement
const foo = bar.baz() as string // 2.式の型情報を上書き
const foo = (bar as string).toLowerCase() // 3.括弧によるアサーションの評価順の変更
```
上記例では、`bar`の`#baz()`**メソッドが返す値とは別に**、`foo`は`string型`と見做されます。

また、型アサーションは式であるため、括弧によって評価順を変更することも可能です。
例では、`bar`の型情報を`string型`に強制しているため、Stringオブジェクトの持つ`#toLowerCase()`メソッドが使用可能です。


ここから少し深入りします。

```ts:型アサーション.基本.不在プロパティ.ts
const num = 777
num.toUpperCase() // コンパイルエラー。
```
`#toUpperCase()`メソッドは`number型`に存在しない、Stringオブジェクトのメソッドであるためコンパイルエラーとなります。というわけで型アサーションを書き加えますが、

```ts:型アサーション.基本.型推論によるエラー.ts
const num = 777 as string // コンパイルエラー
num.toUpperCase()
```
このような、明らかに間違った型によるアサーションもコンパイルで弾かれます。

```ts:型アサーション.基本.anyヤバい.ts
const num = 777 as any
num.toUpperCase() // コンパイルは成功するものの実行時にエラーが投げられる
```
まず`as any`により`num`の型は`any型`へと上書きされ`number型`ではなくなります。

_`any型`は任意の型として扱えるので_ Stringオブジェクトのメソッドである`#toUpperCase()`を呼び出すコードが**コンパイルでは通ります**がしかし、実行時にはエラーを吐きます。`any型`の扱いには気をつけましょう。

---

Generics
--
### こんな奴
- `Foo<T>`
- `new Foo<Bar>()`
- `foo<Bar>()`

### 日本語での呼び名
- ジェネリック
- ジェネリクス
- (特に<T>を指して)ジェネリック型

### ふわっと紹介
例えば`Array<T>`という型は「任意で特定の型としてTを内包するArray」という意味になります。

`Array型`はそれ自体の定義時にどのような型を内包するのかは不明ですが、実際に使用される際にはインスタンスの内包する型が定まっています。例えば`Array<number>`という表記は`number型`のみで構成されたArrayであるという**型**を意味します。

つまり、クラスやインターフェイスの宣言時には特定できない、ある時点で判明する型を別途指定するための仕組みがジェネリクスです。

※先述の[Type Assertion](#Type Assertion)とGenericsとは_似て非なる**別物**_です。ご注意ください。

### コード付き解説
`Array<T>`や`React.Component<P, S>`などという型として用いられている場合が最初に遭遇するケースとして多いかと思います。

#### functionでの利用例
```ts
// この時点でTは任意の型となり得る。
function toArray<T>(...args: T[]): T[] { return args }

// "words"の型は引数の型から推論され、string[](== Array<string>)となる。
const words = toArray('foo', 'bar', 'baz')
words.push('hoge') // OK
words.push(1) // コンパイルエラー
```

#### クラスでの利用例
```ts
class MyObject<T> {

  members: T[]

  constructor(...members: T[]) {
    this.members = members
  }

  pick(index: number): T {
    return this.members[index]
  }

  append(member: T): void {
    this.members.push(member)
  }

}

// コンストラクタからの型推論によりpick()メソッドの戻り値はstring型となるため、以下のようなチェーンも可能。
const withString = new MyObject('foo', 'bar', 'baz')
const str = withString.pick(1).toUpperCase() // 'BAR'

// 以下の記法は"generic parameter"とも呼ばれ、コンストラクタでは型が指定できない場合などに用いる。
const withNumber = new MyObject<number>()
withNumber.append('foo') // コンパイルエラー
```

#### React Component定義での利用例
```ts
import React from 'react'

export interface MyProps {
    hoge: string
}

export interface MyState {
    fuga: string
}

export default class MyComponent extends React.Component<MyProps, MyState> {
  /* 任意の実装 */
}
```
Reactが提供するComponentクラスの場合は継承時にPropsとStateの型が定まるため、実際に使用する際には以下のようなコードになります。

### 参考文献
- https://www.typescriptlang.org/docs/handbook/generics.html - TypeScript公式
- http://ufcpp.net/study/csharp/sp2_generics.html - C#による解説[^AboutC#]

---
以上、2項目でした。

項目は思いつきor要望があり次第、随時追加予定です。

[^AboutC#]: C#の主要開発者であるMicrosoft社はTypeScriptの生みの親