TypeScript基礎 学習記録 #2 (型定義)

## はじめに...TypeScriptとは
JavaScriptを拡張したプログラミング言語であり、JavaScriptのスーパーセット（上位集合）。


:::note info
静的型付けを採用しており、 TypeScriptをJavaScriptに変換する前に**型検査**が発生する。

→ エディタの補完機能が強化され、ミスを防ぎやすく、チーム開発において、型定義に基づくコードの理解や共有が容易になる。

→開発の効率向上につながる。
:::


<details><summary>※型検査</summary>



プログラムの実行中または実行前に、データの型が正しいかどうかを確認するプロセス

</details>

## 学習環境
Visual Studio Code

## TypeScriptのインストール

前提: Node.jsをインストールし、npmコマンドを使用できるようにする。

ターミナルを起動し、npmコマンドでTypeScriptをインストールする。(必要であればsudoを付け加えて管理者権限で実行する）
```terminal
npm install -g typescript
```
## 前提知識
### ・ TypeScriptをJavaScriptに変換
```terminal
tsc ファイル名.ts
```

### ・ ES6へのコンパイラ
```terminal
tsc ファイル名.ts --target ES6
```

https://compat-table.github.io/compat-table/es6/#typescript5_6corejs3
### ・ 変換したファイルを実行
```terminal
node ファイル名.js
```

## 型の書き方
### ・ 変数/型定義...boolean,number,string型
`let 変数名: データ型= 初期値 `の形で定義
```typescript
// boolean型:真偽値
let hasValue: boolean = true;

// number型:数値
let count: number = 10;
let float: number = 3.14;
let negative: number = -0.12;

// string型:文字列
let double: string = "hello";


```
明示した型と異なる型の値を入力した場合エラーとなる。
```typescript
let double: string = 1000;// エラー
```
### ・型注釈と型推論
冗長性を解消するため、なるべく型推論を使うようにする。
```typescript
// 明示的に型を定義している(型注釈)
let count: number = 10;

// 型を指定しなくても自動的に推測してくれる(型推論)
let count = 10; // let count: number
```

### ・ オブジェクト/型定義
object型というものもあるが、書かなくても問題ない。（ほとんど使われないらしい）
```typescript
const person: {
  name: string;
  age: number;
} = {
  name: "John",
  age: 20,
};

// object型
const person1: object = {
  name: "John",
  age: 20,
};
```
定義する型が不足していたり存在しないプロパティを出力しようとするとエラーになる。
```typescript
// エラー
const person: {
  name: string;
  // age: number;
} = {
  name: "John",
  age: 20,
}; 

console.log(person.firstName); // エラー
```

### ・ 配列/型定義

```typescript
const fruit: string[] = ["Apple", "Banana", "Grape"];
```
定義した型とは異なる型の値を入力した場合は弾かれてエラーとなる。
```typescript
const fruit: string[] = ["Apple", "Banana", "Grape"];

fruit.push(30); // エラー
```
### ・ 配列/型定義...Tuple型
異なる型の要素を特定の順序で格納することができる。
任意の順序の要素が追加はできるがコンパイル時にエラーとなる。
```typescript
const variousType: [string, number, boolean] = ["tuple", 43, false];

variousType[0] = "Banana";// ok
variousType.push(20);// ok???
console.log(variousType[3]);// エラー
```

### ・ Enum型
コード内で利用する特定の値を名前付きの定数として扱うことができる。

```typescript
enum PotatoSize {
  SMALL = "SMALL",
  MEDIUM = "MEDIUM",
  LARGE = "LARGE",
}

const potato = {
  hot: true,
  size: PotatoSize.MEDIUM,
};

console.log(potato.size); // MEDIUM
```

### ・ Any型
どの型の値の型も受け入れる特殊な型。
JavaScriptの柔軟さを持ち合わせながら型の制約を一時的に無効化する場合などに使用する。この型はなるべく使わないようにする。

```typescript
let anything: any;

anything = "hello";// 文字列
anything = 21;// 数値
anything = ["bye", 36, false];// 配列
anything = {key: "value"};// オブジェクト

let banana = "banana";
banana = anything;// 型定義済みの変数に代入できる

```

### ・ Union型

複数の型のいずれかの値を持つことができる型を定義するためのもの。
`` 型1 | 型2 | 型3;``のように``|(パイプ演算子)``を利用して複数の型を結合させる。

```typescript
let unionType: number | string = 10;
unionType = "hello"; // ok
unionType = true;// エラー

let unionTypes: (number | string)[] = [20, "hello"]; //配列

```

## ・Literal型
特定の値そのものを型として扱うため、より具体的な値に制限できる型。定義した特定の値以外を設定するとエラーとなる。

```typescript
const banana: "banana" = "banana";
const apple = "apple";// ok

const grape:"kiwi" = "banana";// エラー
```
以下のようにLiteral型とUnion型とを組み合わせることでEnum型のような使い方もできる。Enum型よりも使い勝手がいい？
```typescript
const cloth: {
size: "small" | "medium" | "large" 
} = {
  size: "medium",
};

cloth.size = "small"; 
```
ただ、Enum型とは違ってオブジェクトとしては扱えないことに注意する必要がある。
```typescript
let clothSize: "small" | "medium" | "large" = "medium";
const cloth = {
  size: clothSize,
};

cloth.size = "small"; // エラー:型 "medium" に割り当てることはできない。

```

### ・ Typeエイリアス
型に名前をつけて複雑な型を簡潔に表現できるもの。
コードの可読性を高めるために使われる。

```typescript
type ClothSize = "small" | "medium" | "large";

let clothSize: ClothSize = "medium";
const cloth = {
  size: clothSize,
};
console.log(cloth.size);// medium
```

### ・ 関数/型定義
関数に型を定義する場合、パラメーラと戻り値に型を定義することができる。
```typescript
function add(num1: number, num2: number): number {
  return num1 + num2;
}
console.log(add(1, 2));// 3
```
基本的にパラメータには型を定義する必要があるが、戻り値には型を明示的に定義せずとも型注釈してくれる。
```typescript
function add(num1: number, num2: number) {
  return num1 + num2;
}

console.log(add(1, 2)); // 3
```
パラメータに型を定義しない場合はany型として型注釈される。
```typescript
// (num1: any, num2: any)
function add(num1, num2):number {
  return num1 + num2;
}

console.log(add(1, 2)); // 3
```

### ・ 関数/型定義 ...void型
関数やメソッドで結果を``undefined``として返す（戻り値を設定しない場合や、``return;``のように値を返さない）時に使われる。
``undefined型``とは違い、戻り値を設定していない場合でも使用することができるため、基本的にはvoid型を利用する。

```typescript
function hello(): void {
  console.log("Hello");
}

console.log(hello());// Hello, undefined
```
### ・ null型/undefined型
それぞれ値が存在しないことを表すもの。
null型は値を意図的に設定しない場合に使用される。
一方、undefined型は値が未定義であることを示す。

```typescript
let tmpNull: null = null;// 明示的に設定しない
let tmpUndefined: undefined = undefined;// 未定義として初期化
```

### ・ 関数を保持する変数に型定義をする
関数型において関数を保持する変数に型定義をする場合はアロー関数を使用するとよい。
```typescript
const plusNum = (num1: number, num2: number): number => {
  return num1 + num2;
};

console.log(plusNum(1, 2));// 3
```

### ・ コールバック関数の型定義
type型を用いて、通常の関数と同様にパラメータに型を指定する方法が良さそう。（もっといい書き方ありそう）
```typescript
type CallBack = (num: number) => number;

const plusAndHandle = (num1: number, callBack: CallBack): number => {
  const num2 = callBack(2);
  return num1 + num2;
};

const returnNum2 = (cb: number): number => {
  return cb;
};

console.log(plusAndHandle(3, returnNum2));// 5
```

### ・ unknown型
any型と同じくどんな型の値でも保持できるが、any型とは違ってunknown型の値に対して直接操作を行うことはできない。そのため、柔軟性を確保しつつ誤った型の操作を防ぐことができる。
```typescript
let unknownInput: unknown = true;

//any型同様、どんな型の値でも保持できる
unknownInput = "hello";
unknownInput = 2;

let text: string;
text = unknownInput; // エラー:unknown型は代入ができない。
```
unknown型の値を使うためには、型チェックを行う必要がある。
```typescript
let unknownInput: unknown = "hello";
let text: string;

text = unknownInput// エラー:unknown型は代入ができない。

if (typeof unknownInput === "string") {
  text = unknownInput; // ok
}

console.log(text); // hello
```

### ・ never型
決して値を返さない関数や変数の方を表すもの。
エラーを``throw``する関数や無限ループを含む関数など、正常に修了することのない関数で用いられる。

```typescript
function infiniteLoop(): never {
	while(true){
     // 無限ループ
    }}

function trowError(message: string):never {
	throw new Error(message);// エラーが発生
}
```