TypeScriptの基本

## 目次
- TypeScriptとは？
- 基本的な型付け
  - string型
  - number型
  - boolean型
- 複数の型付け
  - union型
  - literal型
  - union型 + literal型
  - 型に別名をつける
- 配列の型付け
  - tuple型
  - readonlyも使いこなそう
- オブジェクトの型付け
  - 型の命名はtypeかinterface
  - readonlyも使いこなそう
  - どちらでも良いプロパティ
- 関数の型付け
  - 戻り値あり
  - 戻り値なし
  - 関数式
- ジェネリクス
  - どんなデータ型が入ってきても良い関数


## TypeScriptとは？

TypeScriptは、JavaScriptをより安全に書くために拡張された言語である。
「文字列、数値、真偽値」など様々な型がごっちゃになって予想しなかった問題が起こらないように、TypeScriptではあらかじめ型を決めることができる。

＊JavaScriptでは型が決まっていないため「動的型付け言語」と呼ばれ、TypeScriptでは型が決まっているため「静的型付け言語」と呼ばれる。

## 基本的な型付け

### string型

```typescript
let message: string = 'Hello';
```

### number型

```typescript
let x: number = 5;
```

### boolean型

```typescript
let isLoggedIn: boolean = true;
```
真偽値には、「型推論」と言って型を予測してくれる機能が備わっている。
なので、以下のように省略しても真偽値だと認識してくれる。
あえて書くかどうかはチーム内で決めること。

```typescript
let isLoggedIn = true;
```

## 複数の型付け

### union型

ユニオン型では変数が複数の型になり得る。
下記は文字列、もしくは数値の値になり得る。

```typescript
let keyword: string | number;
```

### literal型

リテラル型ではある一つの値にしかなり得ない。
不便だと感じるかもしれないがユニオン型と合わせると便利である。

```typescript
let taxRate: 0.1;
let myEmail: 'taro@gmail.com';
let isPaid: true;
```

### union型 + literal型

リテラル型はユニオン型と組み合わせると非常に便利である。
例えば下記のようにPassかFailにしかなり得ない、2通りの結果以外は受け付けないことが可能になる。

```typescript
let result: 'Pass' | 'Fail';
```

### 型に別名をつける

下記のように繰り返していては冗長である。

```typescript
let englishResult: 'Pass' | 'Fail';
let mathResult: 'Pass' | 'Fail';
let scienceResult: 'Pass' | 'Fail';
```

下記のように型に別名をつければ解決できる。

```typescript
// 大文字で命名すること
type ResultStatus = 'Pass' | 'Fail';

let englishResult: ResultStatus;
let mathResult: ResultStatus;
let scienceResult: ResultStatus;
```

## 配列の型付け

配列の型付けは型の後ろに[]をつけてあげればよい。

```typescript
const scores: number[] = [70, 80, 90];
```

複数の型を付けたければ以下のようにすればよい。
ユニオン型を()で囲い、[]を後ろにつけた形である。

```typescript
const values: (string | number)[] = ['Taro', 50, 'Jiro'];
```

### tuple型

配列の型に順序をつけたい場合はタプル型で書く必要がある。
少し分割代入の形に似ている。

```typescript
const values: [string, number] = ['Taro', 70]
```

### readonlyも使いこなそう

配列は定数（const）で定義することが多いが、変数のように中身を書き換えることができてしまう。
そういう時はreadonlyをつけてあげると中身の書き換えを禁止することができる。

```typescript
const scores: readonly number[] = [70, 80, 90];
const values: readonly [string, number] = ['taro', 70];
```

## オブジェクトの型付け

オブジェクトの型付けも配列とかと同じ構造である。
配列の場合は、`const score: [string, number] = ['taro' 70]`
オブジェクトの場合は、 `const user: {name: string, score: number} = {・・・}`
のように同じ構造になっている。

＊ちなみにオブジェクトを区切る部分は「,」でも「;」でも良い

```typescript
const user: {userName: string; score: number} = {
    userName: 'taro',
    score: 80,
};
```

### 型の命名はtypeかinterface

型に別名をつけることができるが、その方法は２通りある。

```typescript
type User = {
    userName: string;
    score: number;
};

const user: User = {
    userName: 'taro',
    score: 70,
};
```
interfaceの場合は何かを代入しているわけではないので末尾にセミコロンは必要がない。interfaceの方が使われている。

```typescript
interface User {
    userName: string;
    score: number;
}

const user: User = {
    userName: 'taro',
    score: 70,
};
```

### readonlyも使いこなそう

```typescript
interface User {
    readonly userName: string;
    score: number;
}
```

### どちらでも良いプロパティ

emailプロパティはあってもなくてもどっちでも良いという場合、?をつけてあげるとエラーがなくなる。

```typescript
interface User {
    readonly userName: string;
    score: number;
    email?: string;
}

const user: User = {
    userName: 'taro',
    score: 70,
};
```

## 関数の型付け

関数の型付けは引数と戻り値に対して、型を指定してあげればよい。

### 戻り値あり

```typescript
function double(num: number): number {
    return num * 2;
}
```
### 戻り値なし

戻り値がない場合は、戻り値の型をvoidに変えてあげれば良い。

```typescript
function printName(userName: string): void {
    console.log(userName);
}
```
### 関数式

関数式も関数とほぼ同じで、引数と返り値に対して型を決めてあげれば良いだけ。

```typescript
const double = (num: number): number => {
    return num * 2;
}
```

関数式を変数に代入する場合は少し特殊な書き方をする。
この変数は関数式として扱いますよ〜と宣言している形なのかもしれない。

```typescript
let double: (num: number) => number;
double = (num: number): number => {
    return num * 2;
}
```

## ジェネリクス

### どんなデータ型が入ってきても良い関数

以下のような似ている関数があったとする。

```typescript
function printNumberTwice(num: number): void {
    console.log(num);
    console.log(num);
}

function printStringTwice(str: string): void {
    console.log(str);
    console.log(str);
}
```

2つの関数は型が違うが、その他はほぼ同じだ。
こういう時にデータ型をパラメータ化することができる。

```typescript
function printTwice<T>(value: T): void {
    console.log(value);
    console.log(value);
}

printTwice<number>(10);
printTwice<string>('OK');
```

## まとめ

TypeScriptでは型付けをすることでJavaScriptの安全面を強化している。
型は様々な方法で指定できたが、やっていることはとてもシンプルだ。
型をつける、複数の型をつける、型に名前をつける、特定の値しか取れない型をつける、配列・オブジェクト・関数・関数式に型をつける、全て型をつけているだけだ。