When writing an application using TypeScript, you typically use the “typescript” module as a build tool to transpile your TypeScript code into JavaScript. This is usually all you need. However, if you import the “typescript” module in your application code, you get access to the compiler API. This compiler API provides some very powerful tools for interacting with TypeScript code. Some of its features are documented on the TypeScript wiki: Using the Compiler API .
SourceFile contains a representation of the source code itself, from which you can extract the abstract syntax tree (AST) for the code (Abstract syntax tree )
AST:
Represents the syntactical structure of the program as a tree, starting from the SourceFile itself and drilling down into the statements and their building blocks
In general, ASTs are used by compilers or interpreters as an initial step in the processing of the source code
Here, we used ts.Node.forEachChild() to get the children for a node in the AST. There is an alternative to this, ts.Node.getChildren(sourceFile).forEach(), which creates a more detailed AST:
SourceFile: const test: number = 1 + 2;
-SyntaxList: const test: number = 1 + 2;
--VariableStatement: const test: number = 1 + 2;
---VariableDeclarationList: const test: number = 1 + 2
It is also possible to transpile files from disk using the compiler API. Note: if the file you transpile imports other TypeScript files, those will also be transpiled if the compiler can find them.
Code (file test.ts):
import*as ts from"typescript";
const program = ts.createProgram(["src/test.ts"],{});
program.emit();
The test.js file created by the above code:
"use strict";
exports.__esModule=true;
var ts =require("typescript");
var program = ts.createProgram(["src/test.ts"],{});
If you have a Program, you can use that Program to obtain diagnostics for the code. In order to get the compiler errors or warnings, use the getPreEmitDiagnostics()method. As an example, take a look at the following code which prints its own diagnostics.
import*as ts from"typescript";
let test:number="test";// compiler error
const program = ts.createProgram(["src/test.ts"],{});
Another thing that a Program allows you to do is to obtain a TypeChecker for extracting type information from nodes in the AST. The following code obtains a TypeChecker for itself and uses the checker to emit the types of all variable declarations in the code.
The TypeScript compiler API makes it pretty straightforward to create your own custom linter that generates errors or warnings if it finds certain things in the code. For an example, see this part of the compiler API documentation: Traversing the AST with a little linter . Note that the code uses the SyntaxKind of the node (node.kind) to determine the kind of node and then casts the node to its specific type, allowing for convenient access to certain child nodes.
The example above doesn’t create a Program, because there is no need to create one. If the information in the AST suffices for your linter, it is easier and more efficient to just create a SourceFile directly. More advanced linters may need type checking, which means you will need to generate a Program for the code to be linted in order to obtain a TypeChecker.
The documentation for the compiler API includes an example that uses a TypeChecker to extract and emit type documentation for the code: Using the Type Checker
Traverse the AST and generate a list of changes you want to perform on the code (e.g., remove 2 characters starting from position 11 and insert the string “test” instead).
Then, take the source code as a string and apply the changes in reverse order (starting from the end of the source code, so your changes don’t affect the positions where the other changes need to happen).