What TypeScript adds
the same JavaScript, but checked
What it is
TypeScript is JavaScript plus type descriptions. The browser doesn't execute it: before running, the types are erased, and ordinary JavaScript is left. All of the benefit happens before the run, at the moment of checking.
For working with an AI that is decisive. Go back to article 6.3: there
mypy caught a forgotten null check in Python before anything ran.
TypeScript does the same for the frontend — and does it more strictly,
because here types are not an optional extra but the normal way of working.
What it looks like in code
interface City {
name: string;
temp: number | null;
tags?: string[];
}
function report(c: City): string {
if (c.temp === null) return `${c.name}: no data`;
return `${c.name}: ${c.temp > 0 ? "+" : ""}${c.temp}°`;
}
const cities: City[] = [
{ name: "Oslo", temp: 4 },
{ name: "Tromsø", temp: null },
{ name: "Bergen", temp: -2, tags: ["rain"] },
];
cities.forEach(c => console.log(report(c)));tsc: no errors
Oslo: +4°
Tromsø: no data
Bergen: -2°How to read it
interface City { ... } — a description of an object's shape. Not a
class, not code: after compilation nothing is left of it.
temp: number | null — a union, "either one or the other". The most
useful notation in TypeScript: it says outright that the value may be
missing, and the compiler will force you to check.
tags?: string[] — an optional field. Its type is in fact
string[] | undefined.
function report(c: City): string — takes a City, returns a string.
The same thing as a signature in Python (article 6.5), and it works the
same way: it replaces a paragraph of explanation.
What happens without the null check
Remove the if and ask the compiler to check:
function report(c: City): string {
return `${c.name}: ${c.temp.toFixed(1)}°`;
}error TS18047: 'c.temp' is possibly 'null'.The code won't compile. It won't fail for a user, won't slip past the tests — it simply won't build until you add the check.
The same error in Python looked like Item "None" of "str | None" has no attribute "upper", and in JavaScript without types like
Cannot read properties of null already at run time (article 8.4). Three
languages, one class of error, and only here is it caught before the run.
strict isn't an option, it is the point
{
"compilerOptions": {
"strict": true,
"noUncheckedIndexedAccess": true
}
}Without strict the null check is off, and TypeScript turns into
decoration. Switching it on is mandatory.
noUncheckedIndexedAccess is the second most useful setting. With it,
indexing gives T | undefined, because the element may not be there:
const cities = ["Oslo", "Bergen"];
const first: string = cities[5];error TS2322: Type 'string | undefined' is not assignable to type 'string'.The compiler reminds you of the thing everyone forgets: an index can go out of bounds.
How to run it
npx tsc --noEmit # only check, don't build anything
npx tsx app.ts # run directly--noEmit is what you want most often: a check without a build, the
counterpart of mypy --strict.
What to tell the AI
Port this module to TypeScript: interfaces for the data, types
on every function. tsc --noEmit with strict must pass.
Don't change the logic.In tsconfig turn on strict and noUncheckedIndexedAccess.
Fix the errors that appear without disabling the checks and
without as any.That second sentence matters: the simplest way to "fix" a type error is to silence it, and an AI is inclined to do exactly that (article 9.6).
Describe the types for this API's response: here is a sample
JSON. Mark fields that may be absent as optional or | null —
honestly, not "so that it compiles".What to look for
strict: false, or its absence. The null check is off and the main
benefit is lost.
any in the types. Switches checking off completely for that spot.
as to calm the compiler down. That gets its own treatment in article
9.5.
Types written but tsc never run. The same as annotations without
mypy: decoration that has drifted away from the code.
.js files mixed in with .ts. A half-finished migration: there are no
checks in the .js files, and the errors hide there.
Cheat sheet
TypeScript is JavaScript plus types; at run time the types are erased.
interfacedescribes a shape,|is a union,?an optional field.number | nullforces an emptiness check — otherwise the code won't build.strict: trueis mandatory, or there is nonullchecking.noUncheckedIndexedAccess— indexing gives| undefined.npx tsc --noEmitis a check without a build, the counterpart ofmypy --strict.