エンジニアではない自分がTypeScriptを勉強してみた

## はじめに
[Qiita Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)の16日目の担当は、6日目に引き続き[Qiita株式会社](https://qiita.com/organizations/qiita-inc)プロダクトマーケティングGの中泉（[@zumi0](https://qiita.com/zumi0)）が担当します！

6日目には、非エンジニアがSQLをかけるようになるまでにやったことをまとめたので、興味がある方は読んでいただけると嬉しいです。

https://qiita.com/zumi0/items/a20e9e556469edb209a3

さて今回は、エンジニアではない自分がTypeScriptを勉強するために書籍『[実践TypeScript](https://www.amazon.co.jp/dp/B07T477V6G/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』を読んで学んだことをまとめます！

そもそも「なんでTypeScriptを学ぶの？」というところですが、[Qiita株式会社](https://qiita.com/organizations/qiita-inc)のプロダクトである[Qiita](https://qiita.com/)、[Qiita Team](https://teams.qiita.com/) 、[Qiita Jobs](https://jobs.qiita.com/)のフロントエンドはTypeScriptでかかれているので、今回のAdvent Calendarを機に勉強してみました。

## 書籍『[実践TypeScript](https://www.amazon.co.jp/dp/B07T477V6G/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』を読んでみた
今回読んだ書籍『[実践TypeScript](https://www.amazon.co.jp/dp/B07T477V6G/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』は、2部構成です。第1部では導入編ということで、開発環境の設定からTypeScriptの基礎、TypeScriptの型の内容が書かれています。第2部は実践編ということで、ReactやVue.js、ExpressなどのフレームワークとTypeScriptをどう使うかについての内容が書かれています。

今回は主にTypeScriptの基本的な内容である、第1部の内容をまとめていきます。

### TypeScriptを始める
TypeScriptのインストールは、npmを使う場合は以下のコマンドでできます。

```shell
$ npm install -g typescript
```

インストールしたら`tsc`コマンドを使って、`tsconfig.json`の雛形を作成します。`tsconfig.json`は、TypeScriptコンパイラーの設定ファイルです。このファイルの設定を元に、TypeScriptのファイルはJavaScriptのファイルにビルドされます。
`tsconfig.json`の雛形は、以下のコマンドで作成します。

```shell
$ tsc --init
```

TypeScriptのファイルはJavaScriptのファイルにビルドするには、以下のコマンドで行います。

```shell
$ tsc
```

`tsconfig.json`があるディレクトリが、プロジェクトルートになります。ビルドする際は、このディレクトリ以下の対象ファイルがビルドされます。何をビルドして、ビルドしないかも`tsconfig.json`を記入することで、設定が可能です。

### 型注釈（アノテーション）
JavaScriptの課題の一つに、関数の引数や戻り値の型が決まっていないためにエラーが出てしまうということがありました。TypeScriptは、そのJavaScriptの課題を解決することができます。すなわち、TypeScriptでは変数や定数などに型を付与することができます。このことを型注釈（アノテーション）と言います。

型注釈の仕方は、以下のような感じでできます。

```ts
function add(x: number, y: number): number {
    return x+y
}
```

引数の型注釈の方法は、今回であれば`x`と`y`の後に`: number`と記載することで指定しています。関数の戻り値の型注釈は、`function add(x: number, y: number)`の後に`: number`と記載することで指定しています。

さきほどは1つの型を付与していましたが、複数の型を付与することもできます。
例えば、`number`型の値を代入することがほとんどだが`null`かもしれない値を代入するかもしれない状況がある場合は、以下のような記述をすることで解決することができます。型と型を`|`でつないであげればいいだけです。

```ts
function twoTimes(x: number | null) {
    return 2 * x
}
```

### クラスと継承
TypeScriptでは、クラスの構築と継承を行うことができます。クラスは名前とコンストラクタ関数を宣言する必要があります。`new`演算子を使うことで、インスタンス化できます。今回は書籍に掲載されているクラスを引用させていただきます。

```ts
class Creature {
  numberOfHands: number
  numberOfFeet: number
  constructor(numberOfHands: number, numberOfFeet: number) {
    this.numberOfHands = numberOfHands
    this.numberOfFeet = numberOfFeet
  }
}

const creature = new Creature(0,4)
```

上記の`Creature`クラスを継承したクラスは、以下のように書くことができます。`constructor`関数内にある`super`関数は、親クラスのコンストラクタ実行に相当します。こちらも書籍の方から引用させていただきました。

```ts
class Dog extends Creature {
  bark: string
  constructor(bark: string) {
    super(0,4)
    this.bark = bark
  }
  barking() {
    return `${this.bark}! ${this.bark}!`
  }
  shakeTail() {
    console.log(this.barking())
  }
}

const dog = new Dog('bow-bow')
```

### 型推論
TypeScriptの基本で型注釈の話をしました。型注釈は必ずする必要があるわけではありません。また、TypeScriptには変数などの宣言時に代入された値から、その値の型を推論することができます。

例えば`x`という変数に0を代入した場合に推論される型は`number`型になります。

```ts
// 代入した値
let x = 0
```

```ts
// 推論される型
let x: number
```

上記は`let`を使って変数を宣言していますが、`const`を使う場合は型推論が変わります。`const`で宣言された値は固定値になるため、以下のようになります。

```ts
// 代入した値
const y = 0
```

```ts
// 推論される型
const y: 0
```

型推論とは話は変わりますが、`let`を使って`const`のように型を付与することも可能です。

```ts
// 代入した値
let z: 0 = 0
```

```ts
// 型
let z: 0
```

### アップキャストとダウンキャスト
TypeScriptでは抽象的な型をより詳細な型に付与したり、逆に詳細な型を抽象的な型に付与することができます。抽象的な型から詳細な型を付与することをダウンキャスト、逆をアップキャストと言います。ダウンキャストは、より厳密な型を付与したいときにを行います。アップキャストは、提供されている関数の戻り値が指定されていてうまく使えないなどといったときに行うことがあります。

### 型の互換性
TypeScriptでは、型をチェックする際に型の互換性を使っています。どういうことか簡単に説明すると、変数`x`を変数`y`に代入できた場合は互換性があり、代入できない場合は互換性がないと言えます。どういう場合に代入可能かというと、抽象的な型に詳細な型を代入するときは代入可能です。

書籍に記載されている例を引用し確認していきます。

```ts
let n1: 0 = 0
let n2: number = n1  // No Error
let n3: number = 0
let n4: 0 = n3       // Error!
```

ここで変数`n3`は`number`型の値であり、変数`n4`は`number`型よりもより厳密な型になっているため代入不可、すなわち互換性がないと言えます。
逆に変数`n1`を変数`n2`に代入する場合は、より厳密な型からそうではない型への代入になるため代入可能で、互換性があると言えます。

### Generics
Genericsを用いると、型の決定するタイミングを遅らせることが可能です。

本来であれば、以下のように最初に型を付与する必要があります。

```ts
interface Color {
  value: string
}
```

しかし、Gerericsを用いることで型を付与するタイミングをずらすことができます。

```ts
// このタイミングでは型を付与していない
interface Color<T> {
  value: T
}

// このタイミングで型を付与している
const color1: Color<string> = { value: 'red'}
```

### Conditional Types
Conditional Typesは、書籍から引用すると「型の互換性を条件分岐にかけ、型推論を導出する型」だそうです。

どういうことか書籍の例を見ていきます。
以下の例では、`T`の型が`string`型である場合は`true`となり、`T`の型が`string`型でない場合は`false`となります。　

```ts
type IsString<T> = T extends string ? true : false
type X = IsString<'test'> // type X = ture
type Y = IsString<0>      // type Y = false
```



## さいごに
今回は非エンジニアの自分が書籍『[実践TypeScript](https://www.amazon.co.jp/dp/B07T477V6G/ref=dp-kindle-redirect?_encoding=UTF8&btkr=1)』の主に第1部の内容をまとめてみました。大分ボリュームのある内容だったので、一部をピックアップしながらといった内容になりました。まだまだ道なかばといったところですが、TypeScriptがなんとなくわかってきた感じがします。本来であれば実際に使ってみて、その恩恵を受けられると一番いいなと思いました。

---

[Qiita Advent Calendar 2021](https://qiita.com/advent-calendar/2021/qiita)の17日目は、Qiita株式会社 CX向上G の@ohakutsuが担当します！