TypeScript入門（備忘録） ~{型の定義}~

# 【注意】この記事について

- この記事は末尾に記載の書籍の内容をもとに私が学んだことをアウトプット、整理するための記事です。
- 掲載するコードも書籍に記載されているものを参考に作ったものです(ほぼ一緒です)。
- 読む方はJavaScriptの知識がある前提で書いてます。

# 型の定義
TypeScriptでは変数や引数の後ろに`: 型`のように型注釈(Type Annotations)と呼ばれる型情報を付与することで、変数や引数に格納する値を制限できる。

```ts:hello.ts
function hello(name: string) {
  console.log('Hello ' + name);
}
let name: string = 'Taro';
hello(name);
```

型注釈に反する値を代入しようとすると、TypeScriptのコンパイル時にエラーが発生する。
例えば、string型を受け取る定義をしたコードにnumber型の変数を代入するとコンパイルエラーがでる。

```ts:hello.ts
// error TS2345: Argument of type 'number' is not assignable to parameter of type 'string'.
let age: number = 18;
hello(age);
```

また、文字列を定義し、その変数に対し関数を呼び出そうとするエラーが発生。

```ts:hello.ts
const message = 'hello';

// error TS2349: This expression is not callable. Type 'String' has no call signatures.
message();
```

## 変数
TypeScriptは、型の定義以外は、JavaScriptと同じルールで変数を宣言。
使うのは、var、let、constの3つ。変数名の後に、`: 型`の記述を追加して、型注釈とする。

```ts
var 変数: 型 = 値;
let 変数: 型 = 値;
const 変数: 型 = 値;
```

なお、型注釈はつけてもつけなくてもいい(つけたほうがいいです)

```ts
let name = 'Taro';
// or
let name: string = 'Taro';
```
letとvarはどちらも変数を定義するものだが、適用範囲スコープが異なる。

- letはブロックスコープでブロック内のみでアクセス可
- varは関数スコープで関数内ならどこからでもアクセス可

```ts
function calc(isSum: boolean) {
  let a = 100;
  if(isSum) {
    // aが定義された内側のブロックスコープ内の利用のためエラーが起きない
    let b = a + 1;
    return b;
  }
  // error TS2304: Cannot find name 'b'.
  // varで定義した場合はエラーにならないが、letで定義した場合にはエラーになる。
  return b;
}
```

constは値を変更できない定数を宣言するもの。再代入はできない。
let変数と同じブロックスコープ。

```ts
const num: number = 100;

// 値の再代入はコンパイルエラーになる
num = 200;
```

現在のWebフロントエンド開発では、let、constが主に使用されている。


## プリミティブ型
JavaScriptでの使用頻度が高いプリミティブ型のstring(文字列)、number(数値)、boolean(真偽値)はTypeScriptにも対応する型がある。JavaScriptのtypeof演算子を利用した場合に表示される名前と同じ。

```ts
let age: number = 26;
let isDone: boolean = false;
let color: string = '青';
```

異なる型の値を代入しようとすればエラーになる。
型付けで代入された変数は、宣言以降、静的な型付けの対象となる。

```ts
let num: string = 26;
num = '二十六'; // string型のため問題なく代入可能
num = 38;
// string型の変数にnumber型を入れようとしてコンパイルエラーが起きる。
// Type 'number' is not assignable to type 'string'.
```
 
## 配列
配列に型を指定する場合は、その配列を構成する型と[]の表記を用いる。

```ts
const array: string[] = []
array.push('Taro')
array.push(1) // 配列の方を合わないのでエラー
```

## オブジェクト型
オブジェクトはキーとバリューによるデータ形式のインスタンス。
TypeScriptでは、以下のようにキー名と型のペアを指定して、オブジェクトの型を定義。

```ts
{ キー名1: 型1; キー名2: 型2; ... }

let 変数: { キー名1: 型1; キー名2: 型2; ... } = オブジェクト
const 変数: { キー名1: 型1; キー名2: 型2; ... } = オブジェクト
var 変数: { キー名1: 型1; キー名2: 型2; ... } = オブジェクト
```
```ts
// string型のnameとnumber型のageのみを持つオブジェクトの型を定義
const user: { name: string; age: number } = {
  name: 'Taro',
  age: 24
}

console.log(user.name);
console.log(user.age);
```

また、オブジェクトの型の一部またはすべてのプロパティは?をつけることでオプショナル（省略可能）なプロパティとして指定できる。

```ts
function printNmae(obj: { firstName: string; lastName?: string }) {
  // ...
}
// 以下のどちらのパターンでも正常に動作します
printName({ firstName: 'Taro' })
printName({ firstName: 'Taro', lastName: 'Tanaka' })
```

## any
特別な型で基本的には使わない。名前の通りすべての型を許容する型。
特定の値に対して型チェックを適用したくない場合に利用。

```ts
let user: any = { firstName: 'Takuya' }
// 以下のコードはいずれもコンパイルエラーが起こりません
user.hello()
user
user.age(43)
user = 'hello'

// 他の型への代入を行ってもエラーが起きない
const n: number = user
```
anyを利用すると型チェックの機能が動作しなくなるので、TypeScriptを利用している恩恵を受けられなくなる。JavaScriptプロジェクトえおTypeScriptに移行する過程でない限り、anyを利用しないことが望ましい。

## 関数
関数では、引数と戻り値に対して型を定義できる。

```ts
function(引数1: 型1, 引数2: 型2...): 戻り値 {
  // ...
}
```

関数の引数と戻り値にstringを定義。
```ts
function sayHello(name: string): string {
  return `Hello $(name)`
}
sayHello('Taro')
```

オプショナルの引数も定義できる。定義する場合は引数名の末尾に?をつける。
```ts
function sayHello(name: string, greeting?: string): string {
  return `${greeting || ''} $(name)`
  // 論理演算子||は左側の内容がnullやundefined、空文字列であれば右側を表示
}
// どちらも問題なく動く
sayHello('Taro') // Taro
sayHello('Taro', 'Hello') // Hello Taro
```
 
引数にデフォルトの値を設定することもできる。
関数呼び出し時にその引数を指定しなければ、デフォルトの値が使用される。
```ts
function sayHello(name: string, greeting: string 'Hello'): string {
  return `${greeting} $(name)`
}
// どちらも問題なく動く
sayHello('Taro') // Hello Taro
sayHello('Taro', 'Hey') // Hey Taro
```

関数を引数に指定することもできる。
```ts
// 名前とフォーマット関数を引数として受け取りフォーマットを実行しコンソール出力する
function printName(firstName: string, formatter: (name: string) => string) {
  consol.log(formatter(firstName))
}

function formatName(name: string): string {
  return `${name} san`
}

printName('Taro', formatName) // Taro san
```

### 関数の型
関数を引数に設定する場合の記法はこの書き方。
（ここでの引数名は、実際の関数の引数名と対応している必要はない）
```ts
(引数名: 引数の型) => 戻り値の型
```


## 書籍情報

### タイトル
TypeScriptとReact/Next.jsで作る実践Webアプリケーション開発

### 著者
豊島拓也・吉田健人・高橋佳稀

### 出版社
技術評論者

[Amazonで購入する](https://www.amazon.co.jp/TypeScript%E3%81%A8React-Next-js%E3%81%A7%E3%81%A4%E3%81%8F%E3%82%8B%E5%AE%9F%E8%B7%B5Web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA-%E6%89%8B%E5%B3%B6-%E6%8B%93%E4%B9%9F/dp/4297129167/ref=sr_1_1?crid=2B4JS61MAUJNZ&dib=eyJ2IjoiMSJ9.-Jxyepjsyeddmntapzjxy6YTwzPubQBnd2rFIyAXzt1QVotrgB94zNhHkk-VeSQ1iu3-oP2zwV9sHdmBOK1481be_w4urj7VxH4vLCz5OWiYGMif5I-KHXqw0KtOz7IVGZBe3Vj7FADaetBqzEUX-jI1grgwtIW7Dq1gRKihOvfeTwiKO4SoWqusikaSWjNS7YGMg72u-WM92XcNdPNqHjHabvpRpCj5AuR4FoHD-vzDxsBFlekAeQtX49tZOkCYXPEGJ9C5vpYRkgZMYS2DadH54KaypFgwElpU7BcA7Gk.vxtRVwwn2UtyKWyYWuLhYVsMSeNHWJqHp6VHPMGD6-I&dib_tag=se&keywords=typescript%E3%81%A8react%2Fnext.js%E3%81%A7%E3%81%A4%E3%81%8F%E3%82%8B%E5%AE%9F%E8%B7%B5web%E3%82%A2%E3%83%97%E3%83%AA%E3%82%B1%E3%83%BC%E3%82%B7%E3%83%A7%E3%83%B3%E9%96%8B%E7%99%BA&qid=1728204752&sprefix=TypeScript%E3%81%A8%2Caps%2C204&sr=8-1)