Exploration des composants internes du compilateur TypeScript
Le compilateur TypeScript, souvent appelé tsc
, est l'un des composants principaux de l'écosystème TypeScript. Il transforme le code TypeScript en JavaScript tout en appliquant des règles de typage statiques. Dans cet article, nous allons nous plonger dans le fonctionnement interne du compilateur TypeScript pour mieux comprendre comment il traite et transforme le code TypeScript.
1. Le processus de compilation TypeScript
Le compilateur TypeScript suit une série d'étapes pour transformer TypeScript en JavaScript. Voici un aperçu général du processus:
- Analyse des fichiers sources dans un arbre de syntaxe abstraite (AST).
- Reliure et vérification de type de l'AST.
- Émission du code JavaScript de sortie et des déclarations.
Explorons ces étapes plus en détail.
2. Analyse du code TypeScript
La première étape du processus de compilation consiste à analyser le code TypeScript. Le compilateur prend les fichiers sources, les analyse dans un AST et effectue une analyse lexicale.
Voici une vue simplifiée de la manière dont vous pouvez accéder à l'AST et le manipuler à l'aide de l'API interne de TypeScript:
import * as ts from 'typescript';
const sourceCode = 'let x: number = 10;';
const sourceFile = ts.createSourceFile('example.ts', sourceCode, ts.ScriptTarget.Latest);
console.log(sourceFile);
La fonction createSourceFile
permet de convertir du code TypeScript brut en AST. L'objet sourceFile
contient la structure analysée du code.
3. Reliure et vérification de type
Après l'analyse, l'étape suivante consiste à lier les symboles dans l'AST et à effectuer la vérification des types. Cette phase garantit que tous les identifiants sont liés à leurs déclarations respectives et vérifie si le code respecte les règles de type de TypeScript.
La vérification de type est effectuée à l'aide de la classe TypeChecker
. Voici un exemple de création d'un programme et de récupération des informations de type:
const program = ts.createProgram(['example.ts'], {});
const checker = program.getTypeChecker();
// Get type information for a specific node in the AST
sourceFile.forEachChild(node => {
if (ts.isVariableStatement(node)) {
const type = checker.getTypeAtLocation(node.declarationList.declarations[0]);
console.log(checker.typeToString(type));
}
});
Dans cet exemple, TypeChecker
vérifie le type d'une déclaration de variable et récupère les informations de type de l'AST.
4. Code d'émission
Une fois la vérification des types terminée, le compilateur passe à la phase d'émission. C'est là que le code TypeScript est transformé en JavaScript. La sortie peut également inclure des fichiers de déclaration et des cartes sources, selon la configuration.
Voici un exemple simple de la façon d’utiliser le compilateur pour émettre du code JavaScript:
const { emitSkipped, diagnostics } = program.emit();
if (emitSkipped) {
console.error('Emission failed:');
diagnostics.forEach(diagnostic => {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
console.error(message);
});
} else {
console.log('Emission successful.');
}
La fonction program.emit
génère la sortie JavaScript. Si des erreurs surviennent lors de l'émission, elles sont capturées et affichées.
5. Messages de diagnostic
L'une des principales responsabilités du compilateur TypeScript est de fournir des messages de diagnostic significatifs au développeur. Ces messages sont générés lors des phases de vérification des types et d'émission de code. Les diagnostics peuvent inclure des avertissements et des erreurs, aidant les développeurs à identifier et à résoudre rapidement les problèmes.
Voici comment récupérer et afficher les diagnostics du compilateur:
const diagnostics = ts.getPreEmitDiagnostics(program);
diagnostics.forEach(diagnostic => {
const message = ts.flattenDiagnosticMessageText(diagnostic.messageText, '\n');
console.log(`Error ${diagnostic.code}: ${message}`);
});
Dans cet exemple, les diagnostics sont extraits du programme et imprimés sur la console.
6. Transformer TypeScript avec les API du compilateur
L'API du compilateur TypeScript permet aux développeurs de créer des transformations personnalisées. Vous pouvez modifier l'AST avant l'émission du code, ce qui permet de disposer de puissantes personnalisations et d'outils de génération de code.
Voici un exemple de transformation simple qui renomme toutes les variables en newVar
:
const transformer = (context: ts.TransformationContext) => {
return (rootNode: T) => {
function visit(node: ts.Node): ts.Node {
if (ts.isVariableDeclaration(node)) {
return ts.factory.updateVariableDeclaration(
node,
ts.factory.createIdentifier('newVar'),
node.type,
node.initializer
);
}
return ts.visitEachChild(node, visit, context);
}
return ts.visitNode(rootNode, visit);
};
};
const result = ts.transform(sourceFile, [transformer]);
console.log(result.transformed[0]);
Cette transformation visite chaque nœud de l'AST et renomme les variables selon les besoins.
Conclusion
L'exploration des composants internes du compilateur TypeScript permet de mieux comprendre la manière dont le code TypeScript est traité et transformé. Que vous cherchiez à créer des outils personnalisés ou à améliorer vos connaissances sur le fonctionnement de TypeScript, l'exploration des composants internes du compilateur peut être une expérience enrichissante.