TypeScript
TypeChecker
Learn symbol and type resolution with TypeChecker.
What is the TypeChecker?
The TypeChecker is the symbol and type resolver produced by the Program. You obtain it with program.getTypeChecker(). For a node, you fetch its symbol with getSymbolAtLocation and its type with getTypeAtLocation.
const program = ts.createProgram(["app.ts"], {}, host);
const checker = program.getTypeChecker();
const sym = checker.getSymbolAtLocation(node);
const type = checker.getTypeAtLocation(node);
Without the TypeChecker the AST is pure syntax — it has no meaning.
Symbol and Type
A Symbol represents a declaration — a variable, function or class. symbol.getName() returns the declaration's name. A Type carries type information; for a human-readable form you use checker.typeToString(type).
const sym = checker.getSymbolAtLocation(id);
console.log(sym?.getName()); // "greeting"
const t = checker.getTypeAtLocation(id);
console.log(checker.typeToString(t)); // "string"
Exercise Resolve the symbol and print its name
Let the in-memory app.ts source be let greeting = 'merhaba';. Define a CompilerHost, build the program with noLib: true. Obtain the TypeChecker, resolve the symbol of the greeting identifier with getSymbolAtLocation and print its name with getName().
Show example solution
import ts from "typescript";
const fileName = "app.ts";
const sourceText = "let greeting = 'merhaba';";
const host: ts.CompilerHost = {
fileExists: (n) => n === fileName,
readFile: (n) => (n === fileName ? sourceText : undefined),
getSourceFile: (n, lang) =>
n === fileName ? ts.createSourceFile(n, sourceText, lang, true) : undefined,
writeFile: () => {},
getDefaultLibFileName: () => "lib.d.ts",
useCaseSensitiveFileNames: () => true,
getCanonicalFileName: (n) => n,
getCurrentDirectory: () => "",
getNewLine: () => "\n",
};
const program = ts.createProgram([fileName], { noLib: true }, host);
const checker = program.getTypeChecker();
const sf = program.getSourceFile(fileName)!;
const stmt = sf.statements[0] as ts.VariableStatement;
const id = stmt.declarationList.declarations[0].name as ts.Identifier;
const sym = checker.getSymbolAtLocation(id);
console.log(sym?.getName());
Test yourself
-
How is the TypeChecker obtained?
- program.getChecker()
- checker.from(program)
- ts.createChecker(program)
- program.getTypeChecker()
Show answer
program.getTypeChecker() — The TypeChecker is obtained via program.getTypeChecker(); it returns the symbol and type resolver. The other names do not exist on Program.
-
Symbol's name
const checker = program.getTypeChecker();
const decl = (sf.statements[0] as ts.VariableStatement).declarationList.declarations[0];
const sym = checker.getSymbolAtLocation(decl.name);
console.log(sym?.____());
Show answer
const checker = program.getTypeChecker();
const decl = (sf.statements[0] as ts.VariableStatement).declarationList.declarations[0];
const sym = checker.getSymbolAtLocation(decl.name);
console.log(sym?.getName());
-
TypeChecker parts
- program.getTypeChecker()
- Returns the TypeChecker
- getSymbolAtLocation(node)
- Returns Symbol | undefined
- getTypeAtLocation(node)
- Returns a Type
- symbol.getName()
- Gives the declaration's name
Next lesson: AST traversal