Skip to content
Lesson 2 of 15

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 any to silence an error. Fix the cause, or use unknown and narrow.
  • Trusting typeof x === "object". It is true for null, arrays and plain objects alike, so the answer to "which one?" is wrong unless you test null and arrays first.
  • Annotating the obvious. const n: number = 5 adds 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 typeof expression. Run it on null and 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: === null and Array.isArray. A comparison or Array.isArray is itself true or false, so it can be printed directly.
  • Line 4 uses the && idea from the narrowing section. a && b gives b when a is true and a itself (here false) when it is not, so one expression gives the length for a string and false for 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.

Up nextNumbers and MathGetting Started

Discussion

Ask a question, share an insight, or help someone who’s stuck.

Sign in to post a comment or reply.

Loading…