👏

Typescriptの内部構造ってどうなってるのか気になって

2023/03/05に公開

TypeScriptの内部構造は非常に複雑で、TypeScriptの動作を理解するためには、TypeScriptの構成要素を理解する必要があります。TypeScriptは、以下の要素で構成されています。

  1. パーサー
  2. AST(抽象構文木)
  3. 型チェッカー
  4. コンパイラ

パーサー

TypeScriptのパーサーは、TypeScriptのソースコードを解析し、AST(抽象構文木)を作成します。
ASTは、ソースコードの構造を表す木構造であり、TypeScriptの型チェッカーによって使用されます。TypeScriptのパーサーは、TypeScriptの文法に従ってソースコードを解析します。TypeScriptの文法は、ECMAScriptの文法を拡張したものであり、ECMAScriptの文法とほとんど同じです。ただし、TypeScriptの文法には、型注釈などの独自の構文が含まれています。

AST(抽象構文木)

ASTは、TypeScriptのソースコードの構造を表す木構造です。ASTは、パーサーによって作成され、型チェッカーによって使用されます。ASTは、TypeScriptのコードを解析するために使用され、コードの解析には、ASTをトラバースする必要があります。
ASTは、TypeScriptのソースコードの構造を表すため、ASTのノードは、TypeScriptの要素に対応します。ASTのノードには、識別子、リテラル、式、ステートメント、関数宣言、クラス宣言、インターフェース宣言などがあります。
ASTは、TypeScriptの型チェッカーによって使用されます。型チェッカーは、ASTをトラバースし、各ノードの型を決定します。型チェッカーは、型推論などの技術を使用して、ASTのノードの型を決定します。

型チェッカー

TypeScriptの型チェッカーは、TypeScriptのソースコードの構文と型を検証します。型チェッカーは、ASTをトラバースし、各ノードの型を決定します。

型チェッカーは、型推論を使用して、変数の型、関数の引数と戻り値の型を自動的に決定することができます。また、型チェッカーは、型注釈を使用して、明示的に型を指定することができます。型チェッカーは、型安全性を高めるために、型ガードを使用して、型の型情報の収集
TypeScript のコンパイラは、tsc コマンドを実行した時に TypeScript のソースコードから抽象構文木(AST)を生成します。この AST を利用して、コンパイラはプログラム内で使用される型情報を収集します。この型情報には、変数の型、関数の引数や戻り値の型、クラスのメンバーの型、インターフェースのプロパティの型などが含まれます。

型情報の収集の過程で、コンパイラは型推論を行います。型推論とは、明示的に型を指定しなくても、コンパイラが変数や関数などの型を自動的に推論することです。たとえば、以下のコードでは、変数 foo の型は文字列型と推論されます。

const foo = "bar";

型推論は、プログラムの型情報を収集する際に重要な役割を果たしています。

型チェック

型情報を収集した後、コンパイラはプログラムの型チェックを行います。型チェックとは、プログラムが型安全であるかどうかを検査することです。つまり、プログラムのある部分で指定された型が、別の部分で使用される際に正しくマッチするかどうかを確認することです。

TypeScript の型チェックは、以下のような観点から行われます。

変数の代入において、代入先の型が代入元の型と互換性があるかどうかを確認する。
関数呼び出しにおいて、引数の型が関数のシグネチャと互換性があるかどうかを確認する。
プロパティやメソッドの呼び出しにおいて、オブジェクトがそのメンバーを持っているかどうか、また、メンバーの型が互換性があるかどうかを確認する。
型チェックの結果、プログラムが型安全である場合は、コンパイラは JavaScript のコードに変換して出力します。もし、プログラムが型安全でない場合は、エラーを出力します。

型エラーの回避

TypeScript のコンパイラが出力する型エラーは、プログラムの型が互換性のない形で使用されている場合に発生します。型エラーを回避するには、以下のような型情報の収集
次に、収集されたASTから型情報を収集します。これは、ASTをトラバースし、それぞれのノードに対応する型を決定するプロセスです。型情報は、Symbolというオブジェクトによって表現されます。
Symbolは、TypeScriptのコンパイラ内部で使用される型情報の表現です。Symbolには、識別子(名前)、型情報、ノードの種類などが含まれます。

Symbolの種類には、以下のようなものがあります。
・パラメーター
・変数
・関数
・メソッド
・クラス
・列挙型
・インターフェース
・型エイリアス
これらのSymbolを使用して、TypeScriptのコンパイラは型情報を管理します。

型の解決

次に、型の解決を行います。これは、型注釈や型推論によって決定された型の依存関係を解決するプロセスです。

型注釈とは、変数や関数の宣言時に型を指定することです。例えば、以下のコードでのfooの型注釈はstringです。

let foo: string = 'bar';

型推論とは、変数の型をコンパイラが自動的に推論することです。例えば、以下のコードでのbarの型は、numberに推論されます。

let bar = 42;

型の解決は、依存する型が解決された後に行われます。依存する型が解決できない場合は、エラーが発生します。

型チェック

最後に、型チェックを行います。これは、コードが正しい型を使用しているかどうかを検証するプロセスです。
TypeScriptの型チェックは、静的型付けに基づいています。つまり、コンパイル時に型エラーが検出されます。これは、ランタイム時に型エラーが発生することを防ぐために非常に重要です。

型チェックは、収集された型情報を使用して行われます。コンパイラは、ASTをトラバースし、各ノードに対応する型情報を収集し、それを使用して型チェックを行います。

読み込みと解析

TypeScriptコンパイラは、ソースファイルの読み込みと解析から始めます。コンパイラは、ファイルシステムにアクセスして、指定されたソースファイルを読み込みます。読み込まれたファイルは、構文解析器に渡されます。

構文解析器

構文解析器は、ソースコードを解析して、抽象構文木(AST)を生成します。ASTは、ソースコードの構造を表現するデータ構造です。ASTは、コードの意味を把握するために使用されます。

TypeScriptは、ECMAScript仕様を拡張した言語であるため、構文解析器はECMAScriptの構文を解析できる必要があります。構文解析器は、次のステップでソースコードを解析します。
トークン化 - ソースコードをトークンに分割します。トークンは、キーワード、識別子、演算子、リテラルなどの単位です。
構文解析 - トークンを解析して、ASTを生成します。構文解析器は、ECMAScriptの文法ルールに従って、ASTを構築します。
構文解析器は、生成されたASTを型チェッカーに渡します。

型チェッカー

型チェッカーは、ASTを解析して、型情報を収集します。型チェッカーは、次のステップでASTを解析します。

  1. TypeScriptコンパイラは、ソースコードを受け取り、ParserによってソースコードからASTを生成します。
  2. ASTは、TypeCheckerによって解析され、各ノードの型情報が収集されます。TypeCheckerは、ASTをトラバースして各ノードを訪問し、型情報を収集していきます。
  3. TypeCheckerは、変数の型情報を推論するために、変数が宣言されている場所を特定し、変数の型を決定します。TypeScriptでは、型推論が使われ、開発者が明示的に型を指定しなくても、変数の型を推測することができます。
  4. 関数呼び出しの場合は、呼び出される関数の型情報を収集し、引数の型情報と比較します。もし型情報が一致しない場合は、エラーとして検出されます。
  5. TypeCheckerは、継承やインターフェースの実装、ジェネリック型の解決など、より複雑な型情報の収集も行います。
  6. 最後に、TypeCheckerは収集された型情報を利用して、コードの型チェックを行います。もしエラーが検出された場合は、エラーが報告されます。

また、TypeScriptは、エディタやIDEで使用されるIntelliSenseと呼ばれる機能のサポートも充実しています。これにより、コードを書く際に補完機能や型情報のヒントが表示され、開発者が正しいコードを書くのを助けます。

さらに、TypeScriptはJavaScriptとの互換性が高く、JavaScriptのコードをそのまま利用することができます。また、TypeScriptで記述されたコードをJavaScriptに変換するトランスパイラーが提供されているため、TypeScriptで書かれたコードをJavaScriptの環境でも実行することができます。

TypeScriptは、型による静的解析により、開発者が安心して大規模なアプリケーションを開発できるようにすることを目的としています。そのため、TypeScriptは開発者にとって非常に便利なツールとなっています。

Discussion