Type guards
- TypeScript course
- Advanced
- Lesson 51/57
- 5 min
Add a type guard for each node.
Type guard for a node
Writing a type guard for each node type allows external code to safely narrow the node. A guard of the form isNumberNode(n: Node): n is NumberNode narrows n to NumberNode when it returns true.
type NumberNode = { kind: "number"; value: number };
function isNumberNode(n: Node): n is NumberNode {
return n.kind === "number";
}Multiple guards
Writing guards for multiple node types makes complex branching clean. The isNumberNode(n), isStringNode(n), isAddNode(n) guards can also narrow with if chains instead of switch.
function isStringNode(n: Node): n is StringNode {
return n.kind === "string";
}
function isAddNode(n: Node): n is AddNode {
return n.kind === "add";
}
function process(n: Node): string {
if (isNumberNode(n)) return "num:" + n.value;
if (isStringNode(n)) return "str:" + n.value;
return "add";
}Practice Write node type guards
Define the Node discriminated union type ("number" (value: number), "string" (value: string), "add" (left: Node, right: Node)). Define NumberNode and StringNode types. Write isNumberNode(n: Node): n is NumberNode and isStringNode(n: Node): n is StringNode guard functions (each checking with n.kind === "..."). Write a describe(n: Node): string function: if isNumberNode(n) is true, return "num:" + n.value; else if isStringNode(n) is true, return "str:" + n.value; else return "add". Print the result via console.log(describe({ kind: "string", value: "x" })).
Starter code
// Node discriminated union türünü tanımla (kind: number, string, add)
// NumberNode ve StringNode türlerini tanımla
// isNumberNode ve isStringNode guard fonksiyonlarını yaz
// describe fonksiyonunu guard'larla yaz
// describe({ kind: "string", value: "x" }) sonucunu yazdırSample solution
type Node =
| { kind: "number"; value: number }
| { kind: "string"; value: string }
| { kind: "add"; left: Node; right: Node };
type NumberNode = { kind: "number"; value: number };
type StringNode = { kind: "string"; value: string };
function isNumberNode(n: Node): n is NumberNode {
return n.kind === "number";
}
function isStringNode(n: Node): n is StringNode {
return n.kind === "string";
}
function describe(n: Node): string {
if (isNumberNode(n)) return "num:" + n.value;
if (isStringNode(n)) return "str:" + n.value;
return "add";
}
console.log(describe({ kind: "string", value: "x" }));Expected output
str:x
Questions and answers
Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.
1 What is the benefit of writing a type guard for an AST node?
- It makes the code longer
- It increases runtime speed
- It reduces the number of nodes
- It allows external code to safely narrow the node Correct answer
Explanation: A type guard allows external code to narrow a node to the correct type in an if condition; clean branching can also be done with an if chain instead of switch.
2 isNumberNode predicate
function isNumberNode(n: Node): ____ {
return n.kind === "number";
}
function isNumberNode(n: Node): n is NumberNode {
return n.kind === "number";
}
Explanation: The n is NumberNode predicate tells TypeScript that n is a NumberNode when the function returns true.
3 Type guards parts
| Term | Meaning |
|---|---|
isNumberNode(n) |
narrows n to NumberNode |
n is NumberNode |
predicate return type |
n.kind === "number" |
runtime check |
if (isNumberNode(n)) |
narrowing with if chain |