Skip to content
Type Annotations
step 1/8

Reading — step 1 of 8

Learn

~4 min readGetting Started

TypeScript's superpower is types you write down once, checked everywhere. Catching a typo at compile time beats discovering it at 3am in production. This lesson covers the core type vocabulary you'll use every day.

The basic primitives

let count: number = 0;
let name: string = "Alice";
let active: boolean = true;
let nothing: null = null;
let missing: undefined = undefined;

Lowercase number, string, boolean. (Capitalized Number, String, Boolean are the wrapper objects — almost never what you want.)

Inference — let TypeScript figure it out

let count = 0;          // inferred as number
let name = "Alice";      // inferred as string
const pi = 3.14;         // inferred as the literal type 3.14

For let, the inferred type is WIDENED to the general type (number, string) — the variable can be reassigned, so any number must be allowed. For const primitives, TypeScript infers the exact literal type (3.14, "Alice", true), because the value can never change.

Rule: only annotate function signatures, exported APIs, and ambiguous cases. Annotating const x: number = 5 is noise — TypeScript already knows.

Arrays

let scores: number[] = [90, 85, 100];
let names: string[] = ["Alice", "Bob"];
let matrix: number[][] = [[1, 2], [3, 4]];

// Generic syntax (equivalent):
let scores2: Array<number> = [90, 85, 100];

Most code uses T[] — shorter and reads naturally.

Object types

let user: { name: string; age: number } = {
    name: "Alice",
    age: 30,
};

For reusable shapes, use an interface or type (covered later in this chapter).

Tuples — fixed-length, typed positions

let pair: [string, number] = ["Alice", 30];   // exactly 2 elements
pair[0];   // string
pair[1];   // number

Tuples are arrays where each position has a specific type and the length is fixed. Useful for return values like [error, data] or coordinates.

Union types — "this OR that"

let id: string | number = 42;
id = "abc";        // also OK
id = true;         // ✗ compile error

Unions express "could be one of these." Pair with type narrowing to handle each case:

function format(id: string | number): string {
    if (typeof id === "string") {
        return id.toUpperCase();   // TypeScript knows id is string here
    }
    return id.toString();          // and number here
}

Literal types

let status: "active" | "inactive" | "pending" = "active";
status = "foo";    // ✗ compile error — only those three values allowed

A literal type IS a value, used as a type. Combined with unions, it becomes an enum-like "one of these strings."

any — the escape hatch (avoid)

let x: any = 5;
x = "hello";       // OK
x.notAFunction();   // OK at compile time, BOOM at runtime

any opts out of type checking entirely. Useful for migrating JS code to TS, but defeats the purpose elsewhere. Treat any usage of any as a TODO.

unknown — the type-safe any

let x: unknown = JSON.parse(input);
x.length;           // ✗ compile error — you must narrow first

if (typeof x === "string") {
    x.length;       // ✓ safe — narrowed to string
}

Use unknown when you really don't know the shape. The compiler forces you to narrow before using.

void and never

function logIt(msg: string): void {     // void = returns nothing
    console.log(msg);
}

function throwError(): never {           // never = function never returns normally
    throw new Error("!");
}

void for functions that don't return a value. never for functions that throw or loop forever — and as the type of impossible cases (exhaustiveness checks).

Type assertions — "trust me"

const el = document.getElementById("my-input") as HTMLInputElement;
el.value;    // OK because of the assertion

as Type tells TypeScript to TREAT the value as that type. No runtime check — if you're wrong, you get an error later. Use sparingly.

Common mistakes

  • Using any to silence errors — fix the underlying issue or use unknown + narrowing.
  • Annotating obvious things: const x: number = 5 is noise.
  • Forgetting that primitives are lowercaseNumber, String, Boolean are wrappers (avoid).
  • Confusing unknown and anyunknown forces narrowing; any skips checks.

Discussion

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

Sign in to post a comment or reply.

Loading…