tkrd-stack

学習ノート

自分の理解を深めるための技術メモ

← 一覧に戻る

typescript

サバイバル TypeScript

実行環境

  • tsconfig.json 作成方法
npx tsc --init
  • ローカル環境でコンパイルする環境
npm i -g typescript
tsc index.ts

開発環境

npm i -D typescript
npm install --save @types/node

型注釈(型アノテーション)

  • どのような値が代入できるのか制約するものを「型」と言う。
  • 決められた型のみが代入され、プログラムが安全に操作することができる。
const message: string = "hello";
// :string の部分が型注釈

基本的な型

  • boolean:真偽値
  • number:数値
  • string:文字列
  • bigint:大きな整数
  • symbol:一意の値
  • undefined:未定義
  • null:値が存在しない

特殊な型

  • any:何でも代入できる型。値に対する操作の制限がなく、安全でなくなる。(ポケモンで言うメタモン)
  • unknown:any 型と似ていて、なんでも代入できる型。代入した値によって型が変化する。しかし、値に対する操作が制限される。(ポケモンで言うイーブイ)
  • void:値が存在しないことを示す。関数の返り値に何も返しませんよと言う時に使う。
  • never:決して何も返さない時に使う。エラーを投げる関数などに使う。

型エイリアス

  • 既存の型を新たな名前で定義する。
  • 複雑な方を簡素にしたり、コードの可読性を向上させる。

読み取り専用配列

  • 値の変更ができない宣言。

  • readonly 型[] で読み取り専用配列になる。

  • ReadonlyArray<型名>でもできる。

  • 破壊的メソッドを呼び出そうとすることで警告が出るだけであり、実装・コンパイルされた後でメソッドを実行することはできる。

タプル型

  • 配列の要素数と要素の方が固定される。
  • 要素のインデックス毎に型が決まる。

オブジェクト

オブジェクトの型注釈

  • {プロパティ 1:型, プロパティ:型...}の形式で記述する。
  • プロパティに読み取り専用をつけることもできる。

オブジェクトメソッド

  • オブジェクトに関数を持たせることができる。これをメソッドと呼ぶ。

インデックス型

  • インデックス型を利用してオブジェクト任意のキーと値の型を宣言することができる。
  • 任意のキーで値を取得することができる。
  • Record<K, T>を用いても表現できます。
  • 複数のインデックスを設定する場合は注意が必要。[key:string]:number,[key:number]:number は string と number で暗黙的型変換が行われるため、型の競合が発生する。

ショートハンドプロパティネーム

  • プロパティの名前がすでに定義されている変数である場合は、そのプロパティ名を省略できる。

オプションプロパティ(?)

  • 省略可能なプロパティ。

オプショナルチェーン

  • ?.演算子を用いてプロパティに安全にアクセスする。
  • エラーが発生して処理が止まったりしなくなる。

Map

map  オブジェクト

  • キーとキーに対応する値のコレクション。
  • キーはオブジェクトも可能。

map の型注釈(型アノテーション)

  • Map の型注釈は Map<キーの型, 値の型>の形で記述。

Set

set オブジェクト

  • 同じ値が存在しないコレクション。
  • 要素はなんでも可能。

set の型注釈

  • Set<型>で記述。

列挙型(Enum)

列挙型の基本

  • 関連する一連の数値もしくは文字列の集まりを定義する。(曜日、月、色、など)
  • enum キーワードを使って宣言、定義する。
  • 定義された集まりは上から順に 0 から昇順でフリ番される。
  • フリ番のスタートを指定することもできる。

ユニオン型

  • 複数の型の内いずれかを取る値を表現できる。
  • 型 1|型 2|型 3|...の形式で使う。
  • 一つ以上の異なる型の値を同じ変数で扱う場合に使用。

判別可能なユニオン型

  • タグ付きユニオンや直和型と呼ばれることもある。
  • 共通のリテラル型のプロパティを持つ特別なユニオン型
  • 共通のプロパティを利用して、型を判別できる。
  • 特徴
    • オブジェクトの型でユニオンされている。
    • 各オブジェクトの型を判別するためのプロパティ(ディスクリミネータ)を持つ。
    • ディスクリミネータはリテラル型などであること。
      • リテラル
        • 文字
        • 数値
        • 論理
      • null
      • undefined
    • ディスクリミネータがあれば、各オブジェクトの型は固有のプロパティを持っても良い。

インターセクション型

  • 複数の方を一つに結合した新しい型を定義する。
  • 型 1 & 型 2 & ... の形式で宣言する。
  • 定義された新しい型はそれぞれの型が持つすべてのプロパティとメソッドを備える。

制御フロー分析

  • 処理の流れに応じて変数の型を絞り込むことができる。

ユニオン型の曖昧さ

  • ユニオン型で型注釈を設定すると、持たないメソッドやプロパティへのアクセスをするとエラーが発生する。
function showMonth(month: string | number) {
  console.log(month.padStart(2, '0')); //waringが発生
}

制御フロー分析

  • 条件分岐などの制御フローを分析することで、コードが実行されるタイミングで型の可能性を判断している。
function showMonth(month: string | number) {
  if (month === "string") {
    console.log(month.padStart(2, "0")); //waringが発生しない
  }
}

型ガード

typeof

  • 型の曖昧さを回避するために比較演算子で条件判定をして、型を絞り込んだ。このような型のチェックを型ガードという。
function showMonth(month: string | number) {
  if (typeof month === "string") {
    console.log(month.padStart(2, "0"));
  }
}

instanceof

  • js の初期仕様で typeof null をした場合、結果として"object"が返される仕様になってしまっている。
  • 特定のクラスから生成されたインスタンスであるかを確認したい時は instanceof を使用すること。

in

  • in 演算子でオブジェクトが特定のプロパティを持つかを判定することもできる。
  • in 演算子はオブジェクトのプロパティをチェックするために使う。
  • 文字列やプリミティブな型に対しては、=== を使用して比較を行う。

型ガード関数(type guard function)

//TODO

分割代入引数

  • 関数の引数に分割代入を使うことができる。アロー関数でも使える。
  • 引数が配列やオブジェクトの場合、そのオブジェクトの一部を関数で利用したい場合に便利。
function foo([a,b]){
  console.log(a,b);
}
foo([1,2,3]);//1 2
function bar({ a, b }) {
  console.log(a, b);
}
bar({ a: 1, b: 2, c: 3 }); // 1 2

分割代入の型注釈

  • 分割代入引数の右側に型注釈を書く。

非同期処理

  • コード内で時間を要する処理を効率的に扱うことができる。 js はシングルスレッド、シングルプロセスなのでプログラムは基本的に直列に実行される(ブロッキングが発生する)。
  • 非同期処理を用いることで、並列しているかのような処理を実行することができる。 サバイバル TypeScript:非同期処理について一番わかりやすい説明

Promise

  • 非同期処理を見通しよく書くことができる。

  • 非同期操作の最終的な状態と結果を返す。

  • 状態

    • 保留中:pending
    • 履行済み:fulfilled
    • 拒否:reject
  • 結果

    • 解決済み:resolve
    • 拒否:reject

async/await 構文

  • 非同期処理をより直感的に書くことができる。
  • 非同期コードを同期コードのように扱える。
  • Promise の then や catch で書いていたことを async await を使って関数に切り出すことができる。
const promise = new Promise((resolve, reject) => {
  const success = true;
  if (success) {
    resolve('promise resolved');
  } else {
    reject('promise rejected');
  }
});

promise.then((data) => {
  console.log(data);
});
function funcTime (ms: number) {
  return new Promise((resolve, reject) => {
    setTimeout(resolve, ms);
  });
}

async function asyncFuncTime() {
console.log("start");
await funcTime(3000);
console.log("end");
}

asyncFuncTime();

ジェネリクス(generics)

  • 共通のロジックを持ち、型だけを変更したい場合に有効。
  • 型の再利用性が向上し、型の一貫性を保つことができる。
  • 型変数を導入でき、機能の一部を一般化できる。
  • <T>の部分は型の引数として捉える。

モジュール

  • typescript のモジュールシステムは、他のモジュールと共有するコードと、モジュール内部限定のコードを分ける。

export キーワード

  • モジュール内で定義した変数や関数,クラスなどを外部に公開できる
  • ファイルを介して export することで再 export することもできる。

import キーワード

  • export で公開した対象を別のファイルで読み込み使うことができる

export default キーワード

  • default キーワードを使うと、モジュールがデフォルトで 1 つのみを export することを意味する。

  • import の際に別名指定をすることが可能

export と default export の違い

  • export(named export)
    • 複数の値を export するために使う。
    • そのライブラリ内の補助的な関数や定数。
    • ライブラリに含まれる複数のユーティリティ関数などを個別にインポートして使えるようにする場合に named export を使用します。
  • default export
    • 一つの主要な値を export する。
    • ライブラリやモジュールの主要なエクスポート。例えば、ライブラリ全体を 1 つのクラスとして提供する場合に default export を使用します。

type export  と  type import  

  • 型だけを export,import することもできる。

型レベルプログラミング

  • TypeScript は型レベルでプログラミングするための様々な機能を持っている。

typeof

変数名から型を逆算できる。

keyof

  • オブジェクト型の全てのキーを文字列リテラルのユニオン型として取得できる。

ユーティリティ型

  • typescript は既存の方から新しい型を作成するための様々な型操作を提供している。
  • 個人的感想はかなり強力

Required

  • オプションプロパティを必須にする型。

tips

  • 型同士の比較を直接することができない。