TypeScript①（基礎）

### はじめに
この記事は私がTypeScriptについて学んだ内容を
TypeScript①（基礎)
[TypeScript②（型の機能）](https://qiita.com/zgoovw_/items/c44d28f3cd2fdf91219f)
[TypeScript③（ユーティリティタイプ）](https://qiita.com/zgoovw_/items/2d0236f52e85e78d6109)
の3回に分けて網羅的に紹介していきます。

①（基礎）では導入方法と様々な型について簡単な紹介
②（型の機能）では型が実際にどういう働きをするのかについて
③（ユーティリティタイプ）では型変換を容易にするユーティリティ型について

### 参考リンク

- [TypeScript公式ドキュメント](https://www.typescriptlang.org/docs/)
- [サバイバルTypeScript 〜実務で使うなら最低限ここだけはおさえておきたいTypeScript入門〜
](https://book.yyts.org/)
- [TypeScript Deep Dive 日本語版](https://typescript-jp.gitbook.io/deep-dive/)
- [実践TypeScript ~ BFFとNext.js&Nuxt.jsの型定義~ 単行本](https://www.amazon.co.jp/%E5%AE%9F%E8%B7%B5TypeScript-BFF%E3%81%A8Next-js-Nuxt-js%E3%81%AE%E5%9E%8B%E5%AE%9A%E7%BE%A9-%E5%90%89%E4%BA%95-%E5%81%A5%E6%96%87/dp/483996937X/ref=tmm_pap_swatch_0?_encoding=UTF8&qid=&sr=)



# Typescriptの導入
TypeScriptのインストール

```
npm install -g typescript
```

TypeScriptを使用するプロジェクトフォルダを作成し移動したら
以下のコマンドでtsconfig.jsonを作成

```
tsc --init
```

以上でTypeScriptの導入できます。

# tsconfig.jsonによる型チェックの厳密さの調整

初期状態の`strict: true`の指定では以下のルールが一括で有効になっています。

- alwaysStrict
- noImplicitAny
- noImplicitThi
- strictBindCallApply
- strictFunctionTypes
- strictNullChecks
- strictPropertyInitialization

### tscong.jsonに追加ルールを指定して型チェックを弱くする

暗黙的なany型を許可
`"noImplicitAny": false`

null型に他のプリミティブ型の割り当てを許可
`"strictNullChecks": false`

状況によって上記のようにfalse指定することによって型チェックを弱める事ができます。
ただし、これはJavaScriptプロジェクトを段階的にTypeScriptに移行するために許容されるべきであり、TypeScriptを利用する目的から外れてしまわないように注意が必要です。

# 基本の型

### プリミティブ型
`string`, `number`, `boolean`, `symbol`, `bigint`, `null`, `undefined`があります。

### リテラル型
プリミティブ型を細分化したのがリテラル型で、エディターにベタ書きした文字列や数字や真偽値をリテラルを言います。


### boolean型
`false`または`ture`の値を持つ事ができます。

```ts
let flag = true;
```

### number型
16進数、１０進数、８進数、２進数をサポートしています。

```ts
let decimal: number = 42;
let hex: number = oxee;
let octal: number = 0o213；
let binary: number = 0b1001;
```

### string型
文字列を扱います。またダブルクウォート(")、シングルクウォート(')、バッククウォート(`)で囲います。

```ts
let name: string = "Jacob";
name = 'Michael';
let myName: string = `my name is ${name}`;
```

### array型
配列型の記述方法は以下の２つがあります。

- 配列に入る値の型の後ろにブラケット`[]`をつける。

```ts
let data: number[] = [1, 2, 3];
```

- Array型で記述する。

```ts
let data: Array<number> = [1, 2, 3];
```

### tuple型
配列内の型を指定できます。

```ts
let x: [string, number];
x = ["hello", 3]; // OK
x = [3, "hello"]; // Error
x = ["hello", 3, 0]; // Error
```

### any型
any型はどのような値も代入する事ができ、型が不定の時に使われます。
またany型は型チェックを無効にし、コンパイルを通過させることができるので、不定の型でもコンパイルを通してしまう危険な型とも言えます。

### unknown型
unknown型はany型と似ていて、どのような値も代入する事ができ、型が不定の時に使われます。
any型と異なる点は、コンパイルを通さないという事です。そのため型安全なanyと呼ばれることもあります。

### void型
void型はany型とは逆に`undefined`と`null`以外代入することができません。
戻り値を持たない関数の型として利用されます。

### null型/undefined型
全ての型はnullまたはundefiendを代入する事ができ、null型、undefiend型というサブタイプの型を得ることができます。
また、nullは意図的にnullを定義した場合にだけ使う事ができ、undefinedは意図的に限らず　変数に何も代入されていない状態を表す。

### never型
never型は発生し得ない型を表します。

```ts
function log(text: string): never {
  throw new Error(text);
}
function roop(): never {
  while (true) {}
}
```

### object型
object型はプリミティブ以外の値の型で、引数にオブジェクトのみ受け取る関数に使用します。

```ts
const obj = { foo: 'foo' };
const obj2: {} = obj;
```

# 高度な型

### Intersection Types
IntersectionTypesは複数の型をアンバサンド`&`で結合した型です。

```ts
type Address = {
  City: "Seattle";
  state: "WA";
};
type Name = {
  first: "Matthew";
  last: "Smith";
};
type Profile = Address & Name;
```

### Union Types
複数の型のうち一つが当てはまることをします場合に使用します。

```ts
let data: number | string | boolean;
```

### クラス
TypeScriptではクラスのインスタンス化をする際、受け取った引数をコンストラクターからメンバー変数に代入します。

```ts
class Point {
  x: number;
  y: number;

  constructor(x: number, y: number) {
    this.x = x;
    this.y = y;
  }
}
const coordinates = new Point(3, 0);
```

### 継承
継承(extends)すると継承元のすべてのプロパティとメソッドを受け継ぎ、受け継いだ先で、呼び出しと、追加のメンバーの定義をする事ができます。

```ts
class Animal {
  run() {
    console.log("走る！");
  }
}
class Dog extends Animal {
  woof(times: number) {
    for (let i = 0; i < times; i++) {
      console.log("ワン！");
    }
  }
}
const d = new Dog();
d.run();
d.woof(3);
// 結果
// 走る！
// ワン！
// ワン！
// ワン！
```

`super`を使って継承元のプロパティを上書きする事ができます。

```ts
class Base {
  greet() {
    console.log("こんにちは、いい天気ですね。");
  }
}

class Derived extends Base {
  greet(name?: string) {
    if (name === undefined) {
      super.greet();
    } else {
      console.log(`こんにちは！ ${name.toUpperCase()}`);
    }
  }
}

const d = new Derived();
d.greet();           // こんにちは、いい天気ですね。
d.greet("ウィルさん！"); // こんにちは！ ウィルさん！
```

### クラスメンバー修飾子（public・private・protected）

- publicはどこででも参照・実行が可能
- privateは同一のクラスでのみ参照・実行が可能
- protectedは継承先でのみ参照・実行が可能

同一クラス内での検証

```ts
class Base {
  public name1: string;
  protected name2: string;
  private name3: string;
  constructor() {
    this.name1 = "Ichiro";
    this.name2 = "Jiro";
    this.name3 = "Saburo";
  }
  greet1() {
    console.log(`こんにちは！ ${this.name1}`); // OK
  }
  greet2() {
    console.log(`こんにちは！ ${this.name2}`); // OK
  }
  greet3() {
    console.log(`こんにちは！ ${this.name3}`); // OK
  }
}
const human = new Base();
console.log(human.name1); // Ichiro
console.log(human.name2); // error
console.log(human.name3); // error
human.greet1(); // こんにちは！ Ichiro
human.greet2(); // こんにちは！ Jiro
human.greet3(); // こんにちは！ Saburo
```

継承先での検証

```ts
class Base {
  public name1: string;
  protected name2: string;
  private name3: string;
  constructor() {
    this.name1 = "Ichiro";
    this.name2 = "Jiro";
    this.name3 = "Saburo";
  }
}
class Derived extends Base {
  greet01() {
    console.log(`こんにちは！ ${this.name1}`); // OK (public)
  }
  greet02() {
    console.log(`こんにちは！ ${this.name2}`); // OK (protected)
  }
  greet03() {
    console.log(`こんにちは！ ${this.name3}`); // error (private)
  }
}
const human = new Derived();
human.greet01(); // こんにちは！ Ichiro
human.greet02(); // こんにちは！ Jiro
human.greet03(); // error
```

### 列挙型(Enum
列挙型は、関連する値の集合を編成する方法です。
また数値列挙は自動で0から順に割り振られ、代入した時点から再度割り振られます。

```ts
enum Color {
  red,
  white,
  green,
  blue,
  black = 2,
  pink,
  yellow,
}
console.log(Color);
// 結果
// {
//   '0': 'red',
//   '1': 'white',
//   '2': 'black',
//   '3': 'pink',
//   '4': 'yellow',
//   red: 0,
//   white: 1,
//   green: 2,
//   blue: 3,
//   black: 2,
//   pink: 3,
//   yellow: 4
// }
```

文字列列挙は、数字の自動割り当てはありませんが、別ブロックからもプロパティーを追加することが可能です。

```ts
enum Env {
  USER_API = "abcd",
  USER_KEY = "ABCD",
  APP_ID = "0123",
}
console.log(Env);
// {
//   USER_API: 'abcd',
//   USER_KEY: 'ABCD',
//   APP_ID: '0123'
// }

enum Env {
  PUBLIC_KEY = "abcd0123",
}
console.log(Env);
// {
//   USER_API: 'abcd',
//   USER_KEY: 'ABCD',
//   APP_ID: '0123',
//   PUBLIC_KEY: 'abcd0123'
// }
```

[TypeScript②(型の機能)へ](https://qiita.com/zgoovw_/items/c44d28f3cd2fdf91219f)

### 関連記事
[TypeScript③（ユーティリティタイプ）](https://qiita.com/zgoovw_/items/2d0236f52e85e78d6109)