Integration
- TypeScript course
- Advanced
- Lesson 53/57
- 5 min
Build the working compiler by combining all parts.
Integration
A type-safe compiler combines AST model, visitor pattern, type guards, and exhaustive eval function. AST nodes are modeled with discriminated union; visitor pattern enables traversal; type guards ease external narrowing; exhaustive eval safely processes all types.
type Node =
| { kind: "number"; value: number }
| { kind: "string"; value: string }
| { kind: "add"; left: Node; right: Node };
function assertNever(x: never): never {
throw new Error("Unexpected");
}
function evalNode(n: Node): string {
switch (n.kind) {
case "number": return String(n.value);
case "string": return n.value;
case "add": return evalNode(n.left) + evalNode(n.right);
default: return assertNever(n);
}
}Full compiler
A full compiler takes the AST model, walks it with visitor, provides external narrowing with type guards, and evaluates with exhaustive eval. When a new node is added, all parts must be updated; assertNever guarantees this.
const ast: Node = {
kind: "add",
left: { kind: "number", value: 2 },
right: { kind: "string", value: "x" }
};
console.log(evalNode(ast)); // "2x"Practice Write a full compiler
Define an assertNever(x: never): never function (with throw new Error("Unexpected")). Define the Node discriminated union type ("number" (value: number), "string" (value: string), "add" (left: Node, right: Node)). Write an evalNode(n: Node): string function using switch (n.kind): for number return String(n.value), for string return n.value, for add return evalNode(n.left) + evalNode(n.right), for default write return assertNever(n);. Define an ast value of type Node: { kind: "add", left: { kind: "number", value: 2 }, right: { kind: "string", value: "x" } }. Print the result via console.log(evalNode(ast)).
Starter code
// assertNever fonksiyonunu tanımla (never parametre, throw ile)
// Node discriminated union türünü tanımla (kind: number, string, add)
// evalNode fonksiyonunu switch ile yaz, default'ta assertNever çağır
// ast değerini tanımla ve evalNode ile değerlendirip yazdırSample solution
function assertNever(x: never): never {
throw new Error("Unexpected");
}
type Node =
| { kind: "number"; value: number }
| { kind: "string"; value: string }
| { kind: "add"; left: Node; right: Node };
function evalNode(n: Node): string {
switch (n.kind) {
case "number":
return String(n.value);
case "string":
return n.value;
case "add":
return evalNode(n.left) + evalNode(n.right);
default:
return assertNever(n);
}
}
const ast: Node = {
kind: "add",
left: { kind: "number", value: 2 },
right: { kind: "string", value: "x" }
};
console.log(evalNode(ast));Expected output
2x
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 Which patterns are used together in a type-safe compiler?
- Only classes
- Only functions
- Only interfaces
- Discriminated union, visitor, type guard, exhaustive check Correct answer
Explanation: A type-safe compiler uses discriminated union for the AST model, visitor for traversal, type guard for narrowing, and exhaustive check for safe evaluation, all together.
2 add node definition
type Node =
| { kind: "number"; value: number }
| { kind: "string"; value: string }
| { kind: ____; left: Node; right: Node };
type Node =
| { kind: "number"; value: number }
| { kind: "string"; value: string }
| { kind: "add"; left: Node; right: Node };
Explanation: The add node is defined with its own discriminant value "add"; it carries left and right child nodes.
3 Integration parts
| Term | Meaning |
|---|---|
AST modeli |
with discriminated union |
Visitor deseni |
walks the tree |
Type guard'lar |
provides external narrowing |
Exhaustive eval |
safely processes all types |