TypeScript
Diagnostic production
Learn to produce your own diagnostics.
Position information
When a rule violation is found, you report it with position info. node.getStart(sourceFile) gives the node's start offset; ts.getLineAndCharacterOfPosition(sf, offset) returns a { line, character } object. line is 0-indexed.
const start = node.getStart(sf);
const { line } = ts.getLineAndCharacterOfPosition(sf, start);
console.log(`line ${line + 1}: error`);
Collecting errors
To collect errors at once you use an array. On each violation you push text with errors.push(...), and at the end you print with errors.join("\n"). This pattern mirrors TypeScript's own diagnostics mechanism.
const errors: string[] = [];
// on violation:
errors.push(`line ${line + 1}: message`);
console.log(errors.join("\n"));
Exercise Report any types
Create a source with three variables, each on its own line: let a: any = 1;, let b: number = 2; and let c: any = 3;. Write a visit function that finds VariableDeclaration nodes whose type annotation is any and collects an error with its line number into a list. Walk with ts.forEachChild and print one error per line.
Show example solution
import ts from "typescript";
const sourceText = 'let a: any = 1;\nlet b: number = 2;\nlet c: any = 3;';
const sf = ts.createSourceFile("app.ts", sourceText, ts.ScriptTarget.Latest, true);
const errors: string[] = [];
function visit(node: ts.Node) {
if (ts.isVariableDeclaration(node) && node.type?.kind === ts.SyntaxKind.AnyKeyword) {
const { line } = ts.getLineAndCharacterOfPosition(sf, node.getStart(sf));
errors.push(`line ${line + 1}: any`);
}
ts.forEachChild(node, visit);
}
visit(sf);
console.log(errors.join("\n"));
Test yourself
-
What does ts.getLineAndCharacterOfPosition(sf, offset) return?
- A { line, character } object
- Only the line number
- An offset number
- A Type object
Show answer
A { line, character } object — getLineAndCharacterOfPosition returns a { line, character } object where line is 0-indexed. It does not return a Type, a single line number or an offset.
-
Get the line number
const start = node.getStart(sf);
const pos = ts.____(sf, start);
console.log(pos.line + 1);
Show answer
const start = node.getStart(sf);
const pos = ts.getLineAndCharacterOfPosition(sf, start);
console.log(pos.line + 1);
-
Error reporting parts
- node.getStart(sf)
- Gives the start offset
- getLineAndCharacterOfPosition
- Gives line and character
- errors.push
- Adds the error to the list
- errors.join
- Turns the list into text
Next lesson: Summary - Custom type checker