【TypeScript】コンパイラAPIを使用した型の解析 - 型情報を取得・操作する方法
2024-10-25
2024-10-25
TypeScript
のコンパイラAPI
は、TypeScript
のコンパイラ機能にプログラムからアクセスし、コードの型情報を解析したり操作したりするための強力なツールです。これを使うことで、コード解析ツールや静的型チェックツール、コードトランスパイラなどを自作できるようになります。本記事では、TypeScript
のコンパイラAPIを活用して、型情報の取得やAST(抽象構文木)の解析を行う方法を解説します。
コンパイラAPIとは?
TypeScript
のコンパイラAPI
は、TypeScript
コンパイラ(tsc
)の内部機能にアクセスできるAPIセットです。これにより、TypeScript
コードの構文解析や型チェック、AST(抽象構文木)生成などの操作が可能になります。
具体的には、コンパイラAPIを使用することで次のような処理ができます。
- 型情報の取得:ソースコード内の変数や関数の型情報を取得できます。
- ASTの解析:コードをAST(抽象構文木)に変換し、その構造を解析・操作できます。
- コード変換:ASTを操作して、コードを別の形に変換したり、トランスパイルできます。
- カスタム静的解析ツールの作成:独自の型チェックルールを追加する静的解析ツールを作成できます。
コンパイラAPIの基本的な使い方
まずは、コンパイラAPIを利用するための環境を整えましょう。TypeScript
コンパイラAPIはTypeScript
自体に含まれているため、新たにインストールする必要はありません。typescript
パッケージをインストールしていれば、すぐに利用できます。
npm install typescript --save-dev
ASTの生成と解析
コンパイラAPIの中心的な機能の一つは、TypeScript
コードをAST(抽象構文木)に変換し、コードの構造を解析することです。以下は、コードをASTに変換する簡単な例です。
import * as ts from 'typescript';
// ソースコードの文字列
const code = `
function greet(name: string): string {
return 'Hello, ' + name;
}
`;
// ソースコードからASTを生成
const sourceFile = ts.createSourceFile(
'example.ts',
code,
ts.ScriptTarget.Latest,
true
);
// ASTをトラバースして解析する関数
function visit(node: ts.Node) {
// ノードの種類を表示
console.log(ts.SyntaxKind[node.kind]);
// 子ノードを再帰的に訪問
node.forEachChild(visit);
}
// トップレベルのノードからトラバース開始
visit(sourceFile);
このコードでは、ts.createSourceFile
を使用して、文字列で表現されたTypeScript
コードをASTに変換しています。そして、visit
関数を使ってASTの各ノードを再帰的に訪問し、ノードの種類(構文の種類)を表示しています。
型情報の取得
TypeScript
のコンパイラAPIを使うことで、コード内の変数や関数の型情報を取得することができます。次に、型情報を取得する例を紹介します。
import * as ts from 'typescript';
// ソースコードの文字列
const code = `
const age: number = 30;
const name: string = 'Alice';
`;
// `TypeScript`プログラムを生成
const sourceFile = ts.createSourceFile(
'example.ts',
code,
ts.ScriptTarget.Latest,
true
);
// プログラム全体を作成
const program = ts.createProgram(['example.ts'], { noEmit: true });
const checker = program.getTypeChecker();
// ASTをトラバースして型情報を取得する関数
function visit(node: ts.Node) {
if (ts.isVariableDeclaration(node) && node.name) {
const symbol = checker.getSymbolAtLocation(node.name);
if (symbol) {
const type = checker.getTypeOfSymbolAtLocation(symbol, symbol.valueDeclaration!);
console.log(`${symbol.getName()}: ${checker.typeToString(type)}`);
}
}
node.forEachChild(visit);
}
// トップレベルのノードからトラバース開始
visit(sourceFile);
この例では、TypeScript
の型チェッカー(getTypeChecker
)を使用して、変数の型情報を取得しています。typeToString
メソッドを使うことで、型情報を文字列に変換し、可視化しています。例えば、上記のコードを実行すると、age: number
やname: string
のような結果が得られます。
型解析を活用した実際のユースケース
コンパイラAPIを使った型解析は、以下のような場面で非常に有効です。
カスタムリントツールの作成
TypeScript
の標準的なリントツールではサポートされていない特定のコーディング規則を追加したい場合、コンパイラAPIを使って独自のルールを作成できます。例えば、関数名に特定のプレフィックスが必要な場合や、特定の型の使用を制限するルールなどが考えられます。
コード自動生成ツール
コンパイラAPIを使用すると、ASTを操作して、コードを自動生成するツールを作成できます。例えば、TypeScript
の型定義からAPIクライアントを自動生成するツールや、クラスからデータベースのクエリを生成するツールがその一例です。
プロジェクトの型安全性の向上
大規模なプロジェクトで型の整合性をチェックするために、コンパイラAPIを活用してプロジェクト全体の型解析を行い、型のミスマッチや不完全な型定義を発見できます。特に型安全性が重要なプロジェクトで有効です。
ASTを操作する実際の例
ここでは、TypeScript
のコードをASTを通じて操作し、既存のコードに新しい要素を追加する例を示します。例えば、関数に新しい引数を追加する操作です。
import * as ts from 'typescript';
// ソースコード
const code = `
function greet(name: string) {
return 'Hello, ' + name;
}
`;
// ASTの生成
const sourceFile = ts.createSourceFile(
'example.ts',
code,
ts.ScriptTarget.Latest,
true
);
// ノードを変更するためのトランスフォーム関数
function transformer(context: ts.TransformationContext) {
return (rootNode: ts.SourceFile) => {
function visit(node
: ts.Node): ts.Node {
if (ts.isFunctionDeclaration(node)) {
// 関数に新しい引数を追加
const newParam = ts.createParameter(
undefined, undefined, undefined,
ts.createIdentifier('age'),
undefined,
ts.createKeywordTypeNode(ts.SyntaxKind.NumberKeyword)
);
const updatedParams = ts.createNodeArray([...node.parameters, newParam]);
return ts.updateFunctionDeclaration(
node,
node.decorators,
node.modifiers,
node.asteriskToken,
node.name,
node.typeParameters,
updatedParams,
node.type,
node.body
);
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
}
// トランスパイル(ASTの変更を適用)
const result = ts.transform(sourceFile, [transformer]);
// 新しいコードを生成
const printer = ts.createPrinter();
const transformedCode = printer.printFile(result.transformed[0]);
console.log(transformedCode);
この例では、greet
関数に新しい引数age
を追加し、その結果を出力しています。コンパイラAPIを使えば、TypeScript
コードを自由に操作して、必要な変更を自動的に加えることができます。
まとめ
TypeScript
のコンパイラAPIは、コード解析や型情報の取得、ASTの操作を通じて、強力なツールを構築するための基盤を提供します。静的解析ツールの作成、型情報に基づくカスタム処理、自動コード生成など、さまざまな用途に活用できるため、特に大規模なプロジェクトでの型安全性の確保や開発効率の向上に貢献します。コンパイラAPIをうまく活用して、より高度なTypeScript
開発を進めてみましょう。