TypeScriptの基本を学び直す

概要

TypeScriptの基本について学び直す。

JavaScriptの復習

変数のスコープ(scope)

グローバルスコープ

windowオブジェクトのプロパティとして定義されるスコープ。

### ローカルスコープ

関数スコープ

関数内で定義された変数はその関数内でのみ有効。

レキシカルスコープ

関数内で関数が定義された場合、内側の関数から外側の関数の変数にアクセスできる。

ブロックスコープ

if文やfor文などのブロック内で定義された変数はそのブロック内でのみ有効。

constは再代入付加だがイミュータブルではない

varの問題点

  • 同名で変数宣言できてしまう
  • グローバル変数を上書きしてしまう可能性がある
  • 変数の巻き上げによるバグ混入のリスクがある
  • スコープが広い
    • ブロックではなく関数スコープ

ボックス化(boxing)

プリミティブ型をオブジェクト型に変換すること。

プリミティブ型はフィールドやメソッドを持たないためボックス化が必要であるが、JavaScriptでは暗黙的にボックス化される。これを自動ボックス化(auto-boxing)という。

自動ボックス化の変換先のオブジェクトのことをラッパーオブジェクト(wrapper object)と呼ぶ。例えば、booleanならBooleanがラッパーオブジェクトとなる。undefinedとnullにはラッパーオブジェクトはない。

オブジェクト

プリミティブ以外は全てオブジェクト

ジェネレーター

ジェネレーターは関数内でyieldを使って値を返すことができる。

TypeScriptの基本

変数宣言の型注釈(type annotation)

変数に型を付与することができる。

ラッパーオブジェクトを使うこともできるが、ラッパーオブジェクト型はプリミティブ型に代入できない。

また、ラッパーオブジェクト型には演算子を使うことができない。

ラッパーオブジェクト型は原則利用せず、プリミティブ型を使うことが推奨される。

変数宣言の型推論(type inference)

型を推論してくれる。

型強制(type coercion)

型が異なる演算であってもエラーにならない場合がある。

型強制は暗黙的別の型へ変換する仕組みのこと。

リテラル型

特定の値のみを取る型のこと。

リテラル型として利用できるプリミティブ型は次のとおり。

  • string型
  • number型
  • boolean型

any型

どんな型でも代入できる型。

文脈から型推論ができない場合(ex. 型注釈を省略したとき)は暗黙的にany型として扱われる。

オブジェクト

オブジェクトの型注釈(type annotation)

メソッドの型注釈も可能。

object型もあるが、object型はプリミティブ型を除く全てのオブジェクトを表す型であるため、object型を使うことは推奨されない。また、object型は型安全が保証されない。

オブジェクト型のreadonly

プロパティを読み取り専用するための修飾子。

ひとまとめで書くこともできる。

オブジェクト型のオプションプロパティ(optional property)

オブジェクトのプロパティをオプショナルにするための修飾子。

nerver型

値を持たない型。

unknown型

any型と同じくどんな型でも代入できる型だが、unknown型は型安全が保証される。型が不明なときに利用する。

unknown型を使うときは、型アサーション(type assertion)やtypeof、instanceofを使って型を明示的に指定する。

関数

関数宣言の型注釈(type annotation)

関数式の型注釈

アロー関数の型注釈

関数の型宣言(function type declaration)

関数の実装を省略して型だけを宣言することができる。

メソッド構文も可能。

型ガード関数(type guard function)

型が不明なときに型を特定する関数。

アサーション関数(assertion functions)

型アサーションを行う関数。

オーバーロード関数(overload function)

同じ名前の関数に異なる型の引数を取る関数を複数定義すること。

クラス

クラスの型注釈

クラスのコンストラクターの型注釈

クラスのメソッドの型注釈

公称型(nominal type)

型の名前が同じでも別の型として扱うこと。

TypeScriptでは公称型をサポートしていないため、構造型(structural type)として扱われる。

公称型を実現するためには、構造を変える(ex. プロパティを追加する)必要がある。

オープンエンド(open-ended)と宣言マージ(declaration merging)

オープンエンドとは、同名のインターフェースを複数定義しても重複エラーにならない性質のこと。

宣言マージとは、同名のインターフェースを複数定義すると、それらがマージされる性質のこと。

これらの性質の何が嬉しいかというと、例えばライブラリの型定義を拡張するときに有用となる。

型定義ファイルを分割することで必要な型だけをインポートすることができる。

型の再利用

typeof

変数の型を取得する。

keyof

オブジェクトの型からプロパティ名を型として取得する。

ユーティリティ型

Required

全てのプロパティを必須にする(≒オプショナルを取り除く)。

Readonly

全てのプロパティを読み取り専用にする。

Partial

全てのプロパティをオプショナルにする。

Record<Keys, Type>

プロパティのキーと値がそれぞれKeysとTypeであるオブジェクト型を生成する。

Pick<T, Keys>

型TからKeysのプロパティを抽出する。

Omit<T, Keys>

型TからKeysのプロパティを除外する。

Exclude<T, U>

型Tから型Uで指定した型を除外したユニオン型を生成する。

Extract<T, U>

型Tから型Uで指定した型を抽出したユニオン型を生成する。

NoInfer

型Tを推論させない。

Mapped Types

指定した型を元に新しい型を生成する。

インデックスアクセス型(indexed access types)

プロパティの型や配列の要素の型を取得する。

条件付き型(Conditional Types)

条件に応じて型を変更する。

infer

条件付き型の中で使われる型演算子で、型変数を取得する。

ユニオン分配

ユニオン型を分配して、それぞれの型に適用する。

ジェネリクス

型を引数として受け取る型。

所感

これまでJavaScriptについて何度か学んだことがあるが、TypeScriptいぜんにJavaScriptこんなに難しかったっけ...という気持ちになった。

参考