TypeScript
Type queries
Learn custom type queries with TypeChecker.
What is a custom type check?
A custom type checker is a tool that walks the TypeScript AST and applies specific rules. It traverses nodes with ts.forEachChild, recognizes the nodes you care about via type guards like ts.isVariableStatement, and the rules inspect node properties.
import ts from "typescript";
const sf = ts.createSourceFile("app.ts", code,
ts.ScriptTarget.Latest, true);
function visit(node: ts.Node) {
if (ts.isVariableStatement(node)) {
// apply rule
}
ts.forEachChild(node, visit);
}
visit(sf);
Accessing node properties
A VariableStatement carries a declarationList.declarations array. Each VariableDeclaration has a .name (the identifier) and a .type (the type annotation, if any) property. You write your rule against these.
for (const decl of stmt.declarationList.declarations) {
if (!decl.type) {
// no type annotation
}
}
Exercise Count untyped variables
Create a SourceFile from let x = 1; let y: string = "a";. Write a visit function that counts declarations without a type annotation inside each VariableStatement. Walk the tree with ts.forEachChild and print the total.
Show example solution
import ts from "typescript";
const sourceText = 'let x = 1; let y: string = "a";';
const sf = ts.createSourceFile("app.ts", sourceText, ts.ScriptTarget.Latest, true);
let untyped = 0;
function visit(node: ts.Node) {
if (ts.isVariableStatement(node)) {
for (const decl of node.declarationList.declarations) {
if (!decl.type) {
untyped++;
}
}
}
ts.forEachChild(node, visit);
}
visit(sf);
console.log(untyped);
Test yourself
-
How do you tell whether a VariableDeclaration has a type annotation?
- checker.getTypeAtLocation(node) is called
- If node.type is not undefined
- If node.name is not undefined
- node.kind === SyntaxKind.TypeAnnotation
Show answer
If node.type is not undefined — VariableDeclaration.type is of type TypeNode | undefined; it is defined when a type annotation is present. name is always present, there is no TypeAnnotation SyntaxKind, and getTypeAtLocation resolves the type.
-
Type annotation check
for (const decl of stmt.declarationList.declarations) {
if (!decl.____) {
untyped++;
}
}
Show answer
for (const decl of stmt.declarationList.declarations) {
if (!decl.type) {
untyped++;
}
}
-
Type check parts
- ts.isVariableStatement
- Recognizes VariableStatement
- declarationList.declarations
- Iterates declarations
- decl.type
- Gives the type annotation
- ts.forEachChild
- Walks child nodes
Next lesson: Symbol resolution