Step 1 of 8 · Reading · ~5 min
Learn
Getting Started
Type Annotations
TypeScript's central idea is that you write down what kind of value each name holds, and the compiler checks every use against it. By the end of this lesson you can annotate variables and functions, choose between any and unknown, and narrow an unknown value with runtime checks.
The basic primitives
let count: number = 0;
let title: string = "Report";
let active: boolean = true;
let nothing: null = null;
let missing: undefined = undefined;
Always lowercase: number, string, boolean. The capitalized Number, String and Boolean are wrapper objects and almost never what you want.
Inference: let TypeScript work it out
let total = 0; // inferred as number
const pi = 3.14; // inferred as the literal type 3.14
For let the inferred type is widened to the general type, because the variable can be reassigned. For a const primitive, TypeScript keeps the exact literal type, because the value can never change. Rule of thumb: annotate function parameters, return types and ambiguous cases; leave obvious ones alone. const x: number = 5 is noise.
Arrays, objects and tuples
let scores: number[] = [90, 85, 100]; // array of numbers
let point: { x: number; y: number } = { x: 1, y: 2 };
let entry: [string, number] = ["alice", 30]; // tuple: exactly two positions
T[] is "any number of T". A tuple fixes both the length and the type at each position. Reusable object shapes get a name with interface, which comes a few lessons from now.
Union and literal types
let id: string | number = 42; // either one is fine
id = "A-17"; // still fine
let mode: "fast" | "safe" = "safe"; // only these two exact strings
A union (|) means "this or that". A literal type is a single value used as a type; combined in a union it works like a small enum.
any and unknown
let a: any = 5;
a.notAFunction(); // compiles, crashes at runtime
let u: unknown = JSON.parse("[1, 2]");
u.length; // compile error: you must check first
any switches the checker off for that value. unknown means "I do not know yet": the compiler refuses to let you use the value until you prove what it is. Prefer unknown for anything that comes from outside the program.
Narrowing an unknown at runtime
You prove a type with a runtime check, and on the other side of the check the compiler trusts it. a && b means "a and b": b is evaluated only when a is true, so b may rely on what a proved.
const x: unknown = JSON.parse('"hello"');
console.log(typeof x === "string" && x.length); // 5: on the right of &&, x is a string
If x were a number, typeof x === "string" would be false and x.length would never run. The same idea written as a statement is if (typeof x === "string") { ... }, which runs its block only when the condition is true; the conditionals lesson covers if fully, including this kind of narrowing.
typeof returns one of "string", "number", "boolean", "undefined", "object", "function" and a few more. It has two famous blind spots, both returning "object":
typeof null // "object" (a 1995 quirk kept for compatibility)
typeof [1, 2] // "object" (arrays are objects)
Array.isArray([1, 2]) // true (the right test for arrays)
Array.isArray({}) // false
So null is tested with === null, and arrays with Array.isArray, before you fall back on typeof.
void, never and assertions
void is the return type of a function that returns no useful value; never is for functions that throw or loop forever, and for impossible cases. An assertion, value as Type, tells the compiler to treat a value as that type with no runtime check: const nums = JSON.parse(text) as number[] is a promise, not a proof.
Common mistakes
- Using
anyto silence an error. Fix the cause, or useunknownand narrow. - Trusting
typeof x === "object". It is true fornull, arrays and plain objects alike, so the answer to "which one?" is wrong unless you testnulland arrays first. - Annotating the obvious.
const n: number = 5adds nothing. - Believing an assertion checks anything.
as number[]on a JSON string that holds an object compiles and fails later, far from the cause.
Your exercise
Print four facts about a parsed JSON value. The starter parses the line into value, typed unknown, and each fact is one expression inside a console.log(...):
- Line 1 is a
typeofexpression. Run it onnulland on an array and you will see the blind spot described above. - Lines 2 and 3 are the two tests that fix the blind spot:
=== nullandArray.isArray. A comparison orArray.isArrayis itselftrueorfalse, so it can be printed directly. - Line 4 uses the
&&idea from the narrowing section.a && bgivesbwhenais true andaitself (herefalse) when it is not, so one expression gives the length for a string andfalsefor everything else.
The require(...) and JSON.parse(...) lines at the top are plumbing that later lessons explain; leave them as they are. The mistake to watch for is trusting line 1 alone: for [], {} and null it prints the same word.
Discussion
Ask a question, share an insight, or help someone who’s stuck.
Sign in to post a comment or reply.
Loading…