TypeScriptの基本的な文法・型

## はじめに
私がまとめたTypeScriptに関する記事一覧になります。もし興味がありましたらご覧になってください。
* [TypeScriptの基本的な文法・型](https://qiita.com/Hirohana/items/d93820bd6bc514aec116 "TypeScriptにおける基本的な文法・型")
* [TypeScriptの関数・クラスに関する文法と型](https://qiita.com/Hirohana/items/553353c82c8107a3358b "TypeScriptの関数・クラスに関する高度な文法と型")
* [TypeScriptの高度な型(Utility Types、Conditional Types)](https://qiita.com/Hirohana/items/9c85e65c6e09b9f8b5c8 "TypeScriptの高度な型(Utility Types、Conditional Types")

今回は、**TypeScriptの基本的な文法・型**についての記事になります。

## TypeScriptにおける型の階層構造
A の型の値が B の型に代入可能なとき、「A は B のサブタイプ」で「B は A のスーパータイプ」という関係にある。

TypeScript の型のスーパータイプ / サブタイプの関係は以下のようになっている。
![スクリーンショット (1218).png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1220815/16d84354-ab5a-3c72-3d16-7206eb73e104.png)
unknown はすべての型のスーパータイプであり、never はすべての型のサブタイプである。

なおこういった場合、unknown のような存在をトップ型（top type）と呼び、never のような存在をボトム型（bottom type）と呼ぶ。

型の階層構造が上記のようになっているということは以下のように代入可能ということ。

```typescript: index.ts
const a: 'hello' = 'hello'; // String Enum type ('hello' type)
const b: string = a; // String type
const c: any = b; // Any type
const d: unknown = c; // Unknown type
```

## 基本的な型

### any
 * any型はどんな型でも代入を許す
 * any型は型チェックされない
 * 型推論できない変数は暗黙的にany型になる
 * [サバイバルTypeScript any型](https://typescriptbook.jp/reference/values-types-variables/any "サバイバルTypeScript any型")
 
```typescript
let value: any;
value = 1; // OK
value = "string"; // OK
value = { name: "オブジェクト" }; // OK

// Parameter 'name' implicitly has an 'any' type.
function hello(name) {
  console.log(`Hello, ${name.toUpperCase()}`);
}

hello(1); // name.toUpperCase is not a function
```

### unknown
* unknown型は型安全なany型
* unknown型の値は具体的な型へ代入不可
* unknownと型の絞り込み(型ガード、型ガード関数)
* [サバイバルTypeScript unknown型](https://typescriptbook.jp/reference/statements/unknown "サバイバルTypeScript unknown型")

```typescript
let value: unknown;
value = 1; // OK
value = "string"; // OK
value = { name: "オブジェクト" }; // OK

const value: unknown = 10; 
const int: number = value; // NG.

// 型ガード
const value: unknown = "";
if (typeof value === "string") {
  // ここブロックではvalueはstring型として扱える
  console.log(value.toUpperCase());
}

// 型ガード関数
function isObject(value: unknown): value is object {
  return typeof value === 'object' && value !== null;
}
const value: unknown = { a: 1, b: 2 };
// 型ガード
if (isObject(value)) {
  // ここでは、valueはobject型として扱える
  console.log(Object.keys(value));
}
```

### boolean
* 論理型(boolean type)は、trueとfalseの論理値からなる型
* [サバイバルTypeScript boolean型](https://typescriptbook.jp/reference/values-types-variables/boolean "サバイバルTypeScript boolean型")
```typescript
const isOk: boolean = true;
const isNg: boolean = false;
```
### string
* ダブルクォートでもシングルクォートでもまったく同じ文字列型
* テンプレートリテラル(バッククォート`で囲んだ文字列)
* [サバイバルTypeScript string型](https://typescriptbook.jp/reference/values-types-variables/string "サバイバルTypeScript string型")
```typescript
const message: string = "Hello";

const count = 10;
console.log(`現在、${count}名が見ています。`);
```

### number
* 整数と少数の区別がない
* 2進数、8進数、16進数
* 数値の区切り文字(numeric separators)
* 特殊な数値(NaNとInfinity)
* [サバイバルTypeScript number型](https://typescriptbook.jp/reference/values-types-variables/number "サバイバルTypeScript number型")
```typescript
const integer: number = 123;
const decimal: number = 1.23;

0b1010 // 2進数
0o755 // 8進数
0xfff // 16進数

100_000_000 // 1億

const price = parseInt("百円"); //NaN
const infinity = 1 / 0; // Infinity
```
### bigint
* 数値型(2の53乗)よりも大きな整数を扱えるプリミティブ型
* bigint型のリテラルは整数値の末尾にn
* 計算速度はbigintよりも通常の数値(number)の方が高速
* [サバイバルTypeScript bigint型](https://typescriptbook.jp/reference/values-types-variables/bigint "サバイバルTypeScript bigint型")
```typescript
const x: bigint = 100n;
```

### literal
* リテラル型はstring、number、booleanの3種類の型で作成が可能
* リテラル型はマジックナンバーやステートの表現に用いられられる。その際、ユニオン型と組み合わせることが多い
* [サバイバルTypeScript リテラル型](https://typescriptbook.jp/reference/values-types-variables/literal-types "サバイバルTypeScript リテラル型")
```typescript
const isTrue: true = true;
const num: 123 = 123;
const str: "foo" = "foo";

let num: 1 | 2 | 3 = 1;
```
### object
* 基本的に{}を使って、型アノテーションを行う。
* [サバイバルTypeScript オブジェクト型](https://typescriptbook.jp/reference/values-types-variables/object "サバイバルTypeScript オブジェクト型")
```typescript
let profile: {name: string} = { name : "Hiro" };
profile = {birthday: 1912} // エラーが発生。
```

### array
* 配列にはT[]構文、Array<T>構文の2つの型定義が存在
* [サバイバルTypeScript 配列型](https://typescriptbook.jp/reference/values-types-variables/array "サバイバルTypeScript 配列型")
```typescript
let array: number[];
array = [1, 2, 3];

let array: Array<number>;
array = [1, 2, 3];
```
### tuple
* 要素数と型が固定された配列
* [サバイバルTypeScript タプル型](https://typescriptbook.jp/reference/values-types-variables/tuple "サバイバルTypeScript タプル型")
```typescript
function tuple() {
  //...
  return [1, "ok", true];
}

const list: [number, string, boolean] = tuple();
```

### null
* nullは値がないことを示す値
* nullに対してtypeofを用いると"object"が返るので注意
* [サバイバルTypeScript null型](https://typescriptbook.jp/reference/values-types-variables/null "サバイバルTypeScript null型")
```typescript
const x: null = null;

console.log(typeof null); // object
```

### undefined
* 未定義を表すプリミティブな値
* 変数に値がセットされていないとき、戻り値が無い関数、オブジェクトに存在しないプロパティにアクセスしたとき、配列に存在しないインデックスでアクセスしたときにundefinedが返る
* [サバイバルTypeScript undefined型](https://typescriptbook.jp/reference/values-types-variables/undefined "サバイバルTypeScript undefined型")
```typescript
let name;
console.log(name); //undefined

function func() {}
console.log(func()); //undefined

const obj = {};
console.log(obj.name); //undefined

const arr = [];
console.log(arr[1]); //undefined
```
### void
* 戻り値がない関数の戻り値を型注釈するにはvoid型(console.log()など)
* [サバイバルTypeScript void型](https://typescriptbook.jp/reference/functions/void-type "サバイバルTypeScript void型")
```typescript
function print(message: string): void {
  console.log(message);
}
```

### never
* 「値を持たない」を意味するTypeScriptの特別な型
* 値を持たないとは、『例外が必ず発生する関数の戻り値』や『終了しない関数(無限ループ)の戻り値』
* never型には何も代入できない
* never型はどんな型にも代入できる
* [サバイバルTypeScript never型](https://typescriptbook.jp/reference/statements/never "サバイバルTypeScript never型")
```typescript
function throwError(): never {
  throw new Error();
}

function forever(): never {
  while (true) {} // 無限ループ
}

const foo: never = 1; // NG

const nev = 1 as never;
const a: string = nev; // 代入OK
const b: string[] = nev; // 代入OK
```

### type alias(型の別名)
* 名前のついた型のこと。
* typeキーワードを使う。
* [サバイバルTypeScript type alias](https://typescriptbook.jp/reference/values-types-variables/type-alias "サバイバルTypeScript type alias")
```typescript
// プリミティブ型
type Str = string;
// リテラル型
type OK = 200;
// 配列型
type Numbers = number[];
// オブジェクト型
type UserObject = { id: number; name: string };
// ユニオン型
type NumberOrNull = number | null;
// 関数型
type CallbackFunction = (value: string) => boolean;
```

### intersection(交差)
* T & U のように書き、『T型でもありながらU型でもある』を意味する型
* 『オブジェクト型を活用した新しい型を作る』という用途で使われる
* [サバイバルTypeScript intersection型](https://typescriptbook.jp/reference/values-types-variables/intersection "サバイバルTypeScript intersection型")
```typescript
// 既存の型を組み合わせる

type RedColor = {
  red: number;
};

type BlueColor = {
  blue: number;
};


// [RedColor]と[BlueColor]を組み合わせる
type RedColorAndBlueColor = RedColor & BlueColor;

const PurpleColor: RedColorAndBlueColor = {
  red: 50,
  blue: 50,
};
```
### union(合併)
* T | U のように書き、『T型またはU型』を意味する型
* [サバイバルTypeScript union型](https://typescriptbook.jp/reference/values-types-variables/union "サバイバルTypeScript union型")
```typescript
// 複数の型を許容する

let value: number | string = 1;
value = "foo";
value = 2;
```

### symbol
* プリミティブ型の一種で、その値が一意になる値
* シンボルはシンボル名が同じであっても、初期化した場所が違うとfalse
* [サバイバルTypeScript symbol型](https://typescriptbook.jp/reference/values-types-variables/symbol "サバイバルTypeScript symbol型")
```typescript
const s: symbol = Symbol();

const s1 = Symbol("foo");
const s2 = Symbol("foo");
console.log(s1 === s1); // true
console.log(s1 === s2); // false
```

### enum(列挙型)
* 定数のセットに意味を持たせたコード表現
* [サバイバルTypeScript 列挙型](https://typescriptbook.jp/reference/values-types-variables/enum "サバイバルTypeScript 列挙型")
```typescript
enum Position {
  Top = 1, // 1
  Right, // 2
  Bottom, // 3
  Left, // 4
}
```

### 型アサーション
* `式 as 型`という構文で、その式の型を強制的に変えるという意味
* 『値の変換』ではなく、TypeScriptコンパイラが認識する『型』だけが変化することに注意
* 多用するとバグの温床になるため極力使用しない
* [サバイバルTypeScript 型アサーション](https://typescriptbook.jp/reference/values-types-variables/type-assertion-as "サバイバルTypeScript 型アサーション")
```typescript
function getFirstFiveLetters(strOrNum: string | number) {
  const str = strOrNum as string;
  return str.slice(0, 5);
}

// Helloが出力
console.log(getFirstFiveLetters('Hello! World!'));

// ランタイムエラーが発生
console.log(getFirstFiveLetters(123));
```

### as const
* 型アサーションと構文が似ているが、型を変換する危険な機能ではない。
* `式 as const`の構文で記述。
* 基本的には`as const`が付けられた式に登場する各種リテラルを『変更できない』ものとして扱う。
* [サバイバルTypeScript as const](https://typescriptbook.jp/reference/values-types-variables/const-assertion "サバイバルTypeScript as const")
```typescript
// 1. 配列リテラルの型推論結果を配列型ではなくreadonlyのタプル型にする
// const names: readonly ["Hiro", "Hana", "Masa"]
const names = ['Hiro', 'Hana', 'Masa'] as const;

/* 2. オブジェクトリテラルから推論されるオブジェクトのプロパティが全てreadonlyになる。
  const person: {
    readonly name: "Hiro";
    readonly age: 20;
  }
*/
const person = { name: 'Hiro', age: 20 } as const;

/* 3. 文字列・数値・Bigint・真偽値リテラルに対して
      付けられるリテラル型が広がらないリテラル型に固定される。
 */
// let Hiro1: stringと推論される。
const wideningHiro = 'Hiro';
let Hiro1 = wideningHiro;

// as const で定義したらlet Hiro2: "Hiro"と推論される。
const notWideningHiro = 'Hiro' as const;
let Hiro2 = notWideningHiro
```

## 参考

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%B0%E3%83%A9%E3%83%9F%E3%83%B3%E3%82%B0TypeScript-%E2%80%95%E3%82%B9%E3%82%B1%E3%83%BC%E3%83%AB%E3%81%99%E3%82%8BJavaScript%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-Boris-Cherny/dp/4873119049

https://www.amazon.co.jp/%E3%83%97%E3%83%AD%E3%82%92%E7%9B%AE%E6%8C%87%E3%81%99%E4%BA%BA%E3%81%AE%E3%81%9F%E3%82%81%E3%81%AETypeScript%E5%85%A5%E9%96%80-%E5%AE%89%E5%85%A8%E3%81%AA%E3%82%B3%E3%83%BC%E3%83%89%E3%81%AE%E6%9B%B8%E3%81%8D%E6%96%B9%E3%81%8B%E3%82%89%E9%AB%98%E5%BA%A6%E3%81%AA%E5%9E%8B%E3%81%AE%E4%BD%BF%E3%81%84%E6%96%B9%E3%81%BE%E3%81%A7-Software-Design-plus/dp/4297127474

https://qiita.com/uhyo/items/e2fdef2d3236b9bfe74a

https://knmts.com/as-a-engineer-52/

https://www.typescriptlang.org/static/TypeScript%20Types-ae199d69aeecf7d4a2704a528d0fd3f9.png