🙌

Typescriptの仕組みを調べる

2023/03/05に公開

TypeScriptのコンパイルフロー

TypeScriptは、以下のようなコンパイルフローを持っています。

  1. TypeScriptのソースコードを記述する。
  2. TypeScriptコンパイラがソースコードをJavaScriptに変換する。
  3. 変換されたJavaScriptを実行する。
    このようなフローを持つことで、TypeScriptはJavaScriptに比べて多くの静的解析を行うことができます。

TypeScriptの型チェック

TypeScriptは、静的な型チェックを行います。このため、変数や関数の引数、戻り値などに対して型を明示的に指定する必要があります。静的な型チェックにより、実行時のエラーを事前に防ぐことができます。

TypeScriptの型チェックは、以下のような流れで行われます。

  1. ソースコードを解析し、変数や関数の型を推論する。
  2. 型推論できない場合は、明示的に型を指定する必要がある。
  3. 型推論や明示的な型指定に基づき、変数や関数の型チェックを行う。
  4. TypeScriptのコンパイルオプション
  5. TypeScriptのコンパイルオプションを設定することで、さまざまな静的解析を行うことができます。
    たとえば、以下のようなオプションがあります。
    noImplicitAny: 型が暗黙的に any として扱われている箇所をエラーとして扱う。
    strictNullChecks: null および undefined を許容しないようにする。
    noUnusedLocals: 未使用の変数をエラーとして扱う。
    noUnusedParameters: 未使用の関数パラメータをエラーとして扱う。
    これらのオプションを設定することで、より堅牢なコードを記述することができます。

TypeScriptの型推論

TypeScriptは、変数や関数の型を推論することができます。たとえば、以下のコードでは、TypeScriptは変数 x の型を自動的に number と推論します。

let x = 1;

型推論を行うためには、変数や関数の型を明示的に指定する必要がありません。ただし、明示的な型指定を行うことで、コードの可読性を向上させることができます。

TypeScriptの型エラー

TypeScriptは、型チェックを行うことで、コンパイル時にエラーを検出することができます。たとえば、以下のようなコードでは、変数 x に string 型の値を代入しようとしているため、エラーが発生します。

let x: number = 1;
x = "hello"; // Type 'string' is not assignable to type 'number'

このように、型エラーはコンパイル時に検出されます。これにより、実行時のエラーを防ぐことができます。

TypeScriptのジェネリック

TypeScriptは、ジェネリックをサポートしています。ジェネリックを使用することで、複数の型で同じコードを再利用することができます。
たとえば、以下のようなジェネリックな関数を定義することができます。

function identity<T>(arg: T): T {
  return arg;
}

この関数は、引数として与えられた値をそのまま返すだけのものです。<T> という書式は、型引数と呼ばれます。これを使用することで、arg の型が何であれ、その型をそのまま返すことができます。

TypeScriptの型リテラル

TypeScriptは、型リテラルをサポートしています。型リテラルを使用することで、オブジェクトの型を定義することができます。
たとえば、以下のような型リテラルを使用して、オブジェクトの型を定義することができます。

type Person = {
  name: string;
  age: number;
};

このように、型リテラルを使用することで、オブジェクトの型を簡潔に定義することができます。

TypeScriptのインターフェース

TypeScriptは、インターフェースをサポートしています。インターフェースを使用することで、オブジェクトの型を定義することができます。
たとえば、以下のようなインターフェースを使用して、オブジェクトの型を定義することができます。このように、インターフェースを使用することで、オブジェクトの型を簡潔に定義することができます。

TypeScriptのコンパイラAPI

TypeScriptは、コンパイラAPIを提供しています。コンパイラAPIを使用することで、TypeScriptのコンパイラを直接操作することができます。
たとえば、以下のようなコードを使用して、TypeScriptのコンパイラAPIを使用することができます。

import * as ts from "typescript";

const fileName = "file.ts";
const sourceCode = "let x: number = 1;";

const result = ts.transpileModule(sourceCode, {
  compilerOptions: { module: ts.ModuleKind.CommonJS },
  fileName,
});

console.log(result.outputText); // 'var x = 1;'

このように、コンパイラAPIを使用することで、TypeScriptのコンパイル結果を直接操作することができます。

TypeScriptの型システムの仕組み

TypeScriptの型システムは、以下のような仕組みで実現されています。
型推論:変数の初期化時や関数の引数や戻り値の型を推論することで、型を自動的に決定します。
型注釈:明示的に型を指定することで、型を明示的に決定します。
型ガード:型の範囲を狭めることで、型の安全性を高めます。
型エイリアス:型に別名をつけることで、型を簡潔に定義することができます。
ジェネリック:複数の型で同じコードを再利用することができます。
型リテラル:オブジェクトの型を定義することができます。
インターフェース:オブジェクトの型を定義することができます。
これらの仕組みを組み合わせることで、TypeScriptは静的型付けを実現しています。

まとめ

TypeScriptは、JavaScriptに静的型付けを加えた言語です。TypeScriptは、型チェックを行うことで、コンパイル時にエラーを検出することができます。TypeScriptは、ジェネリックや型リテラル、インターフェースなどの機能をサポートしています。また、コンパイラAPIを提供しているため、TypeScriptのコンパイラを直接操作することができます。TypeScriptの型システムは、型推論や型注釈、型ガード、型エイリアスなどの仕組みによって実現されています。

Discussion