【初学者対応】TypeScriptの基本的な型宣言方法を図解でまとめる

# はじめに

年末年始からTypeScriptの勉強に勤しんでいるのですが、完全初学者のため、TypeScriptの概念を1からまず学んでみようということで学習しています。前回は、[TypeScriptを用いた画面表示までの仕組み](https://qiita.com/yuto_h9m8/items/9a4cbcbfc425b3305aa1 "【TypeScript】画面表示までの仕組みを図解で理解する")を図解形式で投稿しましたが、同時並行で型宣言についても勉強していました。しかし、型宣言の種類が予想以上に多い上に、そもそも基本構文すらあまり理解していなかったため、学習がかなり頓挫しました。そこで、今回は下記動画や記事をもとに、TypeScriptの型宣言の方法を完全初学者の自分がわかるレベルまで落とし込んでまとめてみました。下記型宣言を理解して使えるようになることで、大半の型宣言には対応できると思うので、みなさんの理解の一助になれれば幸いです。

参考動画：https://www.youtube.com/watch?v=KQhyHHQrcic
参考記事：https://zenn.dev/akkie1030/articles/9f2304544245b2

# 型宣言の種類(全12パターン)

下図のように、基本的な型宣言パターンは大きく12種類存在します。
(下図では、基本的な構文がどのカテゴリに当てはまるかといった観点で体系化してますので、その点はご了承ください。)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3661690/ac364a33-bf5b-3d26-1464-ed464f25715c.png)

## Pre1. 基本形
変数や型を宣言するときの基本構文についてですが、以下のようになります。

```pre_base.ts
let variable: string // variable:変数,string：型(※型はnumber,booleanなど複数ある)
variable = "Hello World" // 代入
```

### 1. プリミティブ型
プリミティブ型とは、変数と型を宣言している基本的な構文の型です。上記基本形に沿って記述すると下記のようになります。

```primitive.ts
// 宣言
let primitive: string

// 代入
primitive = "hello japan" // OK
primitive = 0 // NG(宣言時と異なる型の値は入れられない)

// 出力
console.log(primitive)
```

### 2. リテラル型
リテラル型とは、プリミティブ型に対して特定の値で宣言する構文の型です。下記ソースコードを確認すると、プリミティブ型と比較して宣言の型の部分が`string`から`"hello"`と文字列に変わっていることが確認できます。

```literal.ts
// 宣言
let literal: "hello"

// 代入
literal = "hello" // OK
literal = "Good Morning" // NG(宣言時と異なる文字列の値は入れられない)

// 出力
console.log(literal)
```

### 3. オブジェクト型
オブジェクト型とは、プリミティブ型に対してオブジェクト形式で宣言する構文の型です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が`string`から`{name: string, age: number}`へ変わっていることが確認できます。また、パラメータに`?`を付与することで、オプションな変数にすることも可能です。

```object.ts
// 3-1. オブジェクト型の基本形
// 宣言
let object: {name: string, age: number}

// 代入
object = {name: "Kota", age: 25} // OK
object = {name: "Kota"} // NG(ageに対応する引数が指定されていない)

// 出力
console.log(object)


// 3-2. オブジェクト型のパラメータをオプション化
// 宣言
let object: {name: string, age?: number}

// 代入
object = {name: "Kota", age: 25} // OK
object = {name: "Kota"} // OK
object = {age: 27} // NG(必須パラメータのnameに対応する引数が指定されていない)

// 出力
console.log(object)
```

### 4. 型エイリアス
型エイリアスとは、オブジェクト型からさらに型宣言をエイリアスに分けて書く方法です。ここでは、型宣言が長くなったり他で使い回したいとなった場合に使える方法です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が`string`から`type Person = {name: string, age: number}`へ変わっていることが確認できます。

```alias.ts
// 宣言
type Person = {name: string, age: number} // 型エイリアス
let object: Person

// 代入
object = {name: "Kota", age: 25} // OK
object = {name: "Kota"} // NG(ageに対応する引数が指定されていない)

// 出力
console.log(object)
```

### 5. 配列型
配列型とは、プリミティブ型に対して配列形式で宣言する構文の型です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が`string`から`string[]`となっています。

```array.ts
// 宣言
let strArray: string[] = []

// 挿入
strArray.push("Hello! ", "My Name is ", "Kota. ") // OK
strArray.push(123) // NG(宣言時と異なる型の値は入れられない)

// 出力
console.log(strArray)
```

### 6. 配列Object型
配列Object型とは、配列型とObject型を組み合わせた構文の型です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が`string`から`{name: string, age: number}[]`と配列型及びオブジェクト型が融合した型になっていることが確認できます。

```array_object.ts
// 宣言
let objectArray: {name: string, age: number}[] = []

// 挿入
objectArray.push({name: "Yutaka", age: 28}) // OK
objectArray.push({name: "Yutaka"}) // NG(ageに対応する引数が指定されていない)

// 出力
console.log(objectArray)
```

### 7. ユニオン型
ユニオン型とは、プリミティブ型に対して単一の型だけでなく複数の型が宣言できる構文の型です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が`string`から`string | number`と文字列型もしくは数値型に対応させる宣言に変換できます。実際に、代入の部分で文字列と数値両方に対応できます。他にも、プリミティブ型だけでなくリテラル型での宣言にも使用することができます。

```union.ts
// 宣言
let union: string | number

// 代入
union = "hello" // OK
union = 123 // OK
union = true // NG(定義した型に対応していない)

// 出力
console.log(union)
```

### 8. 列挙型
列挙型とは、型指定をせずに、複数の定数に値を持たせたリストを生成する宣言方法です。下記ソースコードより、事前にプロパティ(Dog,Catなど)と値("犬","猫"など)を指定することで、あたかも辞書かのように変数を扱うことが可能です。

```enum.ts
// 宣言
enum Animals {
  Dog = "犬",
  Cat = "猫",
  Zebra = "シマウマ",
  Squirrel = "リス",
}

// 拡張
enum Animals {
  Gorilla = "ゴリラ",
};

// 出力
console.log(Animals.Dog) // OK("犬"が出力)
console.log(Animals.Gorilla) // OK("ゴリラ"が出力)
console.log(Animals.Monkey) // NG(定義されていないので"undefined"が出力)
```

### 9. 型推論
型推論とは、型指定をせずに型を推定させる方法です。下記ソースコードより、プリミティブ型と比較して宣言の型の部分が存在せず、宣言の段階で定義された値に基づいて、型が推論されていることが確認できます。

```guess.ts
// 宣言
let strInf = "hello" // 推論結果：string型
let numInf = 123 // 推論結果：number型

// 代入
strInf = "good!" // OK
strInf = 123 // NG(文字列ではない)
numInf = 123 // OK
numInf = "good!" // NG(数値ではない)

// 出力
console.log(strInf)
console.log(numInf)
```

## Pre2. 関数化
関数化についての基本的な構文ですが、下記のようになります。下記では、アロー関数を表していますが、他にも関数を表現する方法はいくつか存在しますが、ここでは割愛します。（気になる方は下記のリンクを覗いてみてください。）
```pre_function.ts
const variable = () : string => { // 基本形がアロー関数化したもの
  // 処理
}
```

TypeScript関数：https://typescriptbook.jp/reference/functions

### 10. 関数型
関数型とは、プリミティブ型に対して関数型で表現する方法です。上記の関数化の構文に沿って書くと下記のようになります。()の中に型付き変数を宣言することで、関数の中で変数が使える仕組みになっています。また、可変長引数化することで、引数の個数を指定せずに書くことができます。

```function.ts
// 10-1. 関数型の基本形(オプション化も可能)
// 宣言
const sum = (x: number, y: number): number => {
  return x + y;
}

// 出力
console.log(sum(1,2)) // OK
console.log(sum(1)) // NG(引数が足りない)
console.log(sum(1,"2")) // NG(正しい型になっていない)

// 10-2. 関数型のパラメータを可変長引数化
// 宣言
const sum = (...numbers: number[]): number => {
  return numbers.reduce((acc, i) => acc + i, 0); 
}

// 出力
console.log(sum(1,2,3)) // OK(出力:6)
console.log(sum(1,2,3,4,5,6)) // OK(出力:21)
console.log(sum(1,2,3,4,5,"6")) // NG(string型が混ざっている)
```

### 11. 型の共通化
関数型に対して型を共通化する構文の型も存在します。下記ソースコードより、関数型と比較して`(x: number, y: number)`から`<T,U>(key1: T, key2: U)`と型の部分を関数化できていることが確認できます。これにより、関数の型の使い回しができるといった利点があります。

```common.ts
// 宣言
const commonType = <T,U>(key1: T, key2: U) : String => {
  return String(key1) + "は" + typeof key1 + "型 / " + String(key2) + "は" + typeof key2 + "型"
}

// 出力
console.log(commonType<string,number>("Taro",23)) // OK
console.log(commonType<boolean,boolean>(true,false)) // OK
console.log(commonType<boolean,boolean>("Taro",23)) // NG(Taro/23ともにboolean型ではない)
```

## Pre3. クラス化
クラス化についての基本的な構文ですが、下記のようになります。基本形や関数化と比較すると少し複雑にはなりますが、クラス内に関数の処理(プロパティ,コンストラクタ,メソッド)を書いて、クラス外でクラス内の処理を呼び出す仕組み(インスタンス化)となっています。

```pre_class.ts
class Class { // クラス名

  // プロパティ
  private variable: string

  // コンストラクタ
  constructor(variable: string){
     this.variable = variable
  }

  // メソッド
  public test(): string { 
    return `${this.variable} is test.`;
  }
}

// インスタンス
const person = new Class("テスト")
```

### 12. クラス型
クラス型とは、プリミティブ型に対してクラス型で表現する方法です。上記の関数化の構文に沿って書くと下記のようになります。

```class.ts
// クラスの宣言
class Person {

  // プロパティ(型定義)
  private name: string
  private age: number

  // コンストラクタ(初期実行)
  constructor(name: string, age: number){
     this.name = name
     this.age = age
  }

  // メソッド
  public greeting(): string {
    return `Hello My name is ${this.name}. I'm ${this.age} years old.`;
  }
}

// クラスへの代入(インスタンス化)
const person = new Person("Taro", 23)

// 出力
console.log(person.greeting())
```

# 最後に
今回は、TypeScriptの基本的な型宣言方法を12個に分けて図解でまとめてみました。上記で解説した構文は基本的な構文になるため、応用的な構文も考慮すると体系化の枠組みにとらわれず使えるようになるかと思いますので、初学段階での整理に役立てていただければと考えています（個人的にもそう願ってます笑）。個人的にはこの整理で型宣言の種類がかなり明確になったので、次は実際にコーディング等をして実装に役立てていけるように頑張ります。

最後に、今回記載したソースコードですが、実際にどんな形で動くか、エラーが出るかなど色々試してみたい場合には、下記のサイトで色々触ってみてください。

TypeScript実行プラットフォーム：https://www.typescriptlang.org/play