1type User = { name: string; age: number };2const text = '{"name":"Ada","age":"36"}';const text = '{"name":"Ada","age":36}';3const user = JSON.parse(text) as User;const data: unknown = JSON.parse(text);4console.log(user.age + 1);console.log(data.age + 1);if (isUser(data)) console.log(data.age + 1);5else console.log("bad data");tsctype checker!✓6function isUser(x: unknown): x is User {7 return typeof x === "object" && !!x8 && "name" in x && "age" in x9 && typeof x.name === "string"10 && typeof x.age === "number";11}(no check here yet)✗✓$ node app.js361bad data37TSJS"age":"36""age":36
Left: app.ts, your code (back) and the type guard (front)Right: the server that sends data, tsc, and the laptop that runs the programTokens: the JSON data, the program going to tsc, and app.js going to Node.jsLeft: app.ts as two code cards, lines 1–5 and the type guard on lines 6–11. Right: a server sending JSON, tsc, and a laptop running app.js. Cast with as User, the data is never checked and "36" + 1 prints 361. Typed unknown, tsc demands a check; the guard rejects the bad reply (bad data) and lets the good one through (37). In a real app the text on line 2 comes from a server (for example with fetch) or a file. Here it is written into line 2 so the whole program runs as it is.

Trusting the data

  1. Real programs read data from outside: a server, a file, a form. It arrives as text, often JSON. This server sends {"name":"Ada","age":"36"}. Look closely: "36" is in quotes, so age is a string.

Making tsc ask

At run time

In real projects

What happens

;; step 1/9 · outside
the server replies with text (JSON):
  {"name":"Ada","age":"36"}

"name": "Ada"   a string
"age":  "36"    in quotes: a string, not a number

   1  type User = { name: string; age: number };
>  2  const text = '{"name":"Ada","age":"36"}';

In a real app the text on line 2 comes from a server (for example with fetch) or a file. Here it is written into line 2 so the whole program runs as it is. Every output shown is real: tsc 5.9 with --strict, then Node.js. The cast version prints 361; the guarded one prints bad data, and 37 once the data is right.