Capítulo 2 de 36

Chapter 2: Everyday Types

Core Idea

The core vocabulary for typing JavaScript values: primitives, arrays, object types, unions, literal types, and the two ways to name a shape (type vs interface) — the building blocks every more advanced TypeScript feature composes from.

Key Concepts

  • Primitives: string, number (no separate int/float — everything numeric is number), boolean. Never use the capitalized wrapper types (String, Number, Boolean) — those refer to rarely-used built-ins.
  • Arrays: number[] or Array<number> (equivalent). [number] is a different thing — a tuple.
  • any: opts a value out of type-checking entirely (property access, calls, assignment — all become silently legal). Useful as an escape hatch, but noImplicitAny should be on so it's never chosen for you.
  • Type annotations go after the thing being typed (let x: string, not string x), and are almost always optional — TypeScript infers from initializers.
  • Function typing: parameter annotations after the name (function f(name: string)); return type annotations after the parameter list (function f(): number), usually unnecessary since TS infers from return statements. Promise-returning functions annotate as Promise<T>.
  • Contextual typing: an anonymous function's parameters get inferred types from the context it's used in (e.g. .forEach((s) => ...) infers s from the array's element type) — no annotation needed.
  • Object types: { x: number; y: number }; property separator can be , or ;; an unannotated property is implicitly any.
  • Optional properties (last?: string): reading one gives T | undefined — must narrow (obj.last !== undefined) or use ?. before use.
  • Union types (number | string): a value that could be any one of the listed types. You can only call operations valid for every member without narrowing first (typeof, Array.isArray, discriminant checks, etc.). A property/method common to all union members is usable without narrowing.
  • Type aliases (type Point = {...}) vs interfaces (interface Point {...}): both name an object type and are structurally interchangeable in most uses. The real difference: an interface can be reopened later (declaration merging, extends) — a type alias cannot be redeclared, only combined via & intersections. Rule of thumb: default to interface; reach for type when you need a union, tuple, or other non-object shape, or intersection-based composition.
  • Type assertions (as T or <T>value outside .tsx): tell TS "trust me, this is more/less specific" — removed at compile time, no runtime check. Only allowed between compatible types; force an incompatible one via double assertion (as any as T / as unknown as T).
  • Literal types: "hello", 42, true as types-of-one-value. Alone they're useless; combined into unions ("left" | "right" | "center") they express enums of allowed values without a runtime enum. boolean itself is just true | false.
  • Literal inference widening: const obj = { counter: 0 } types counter as number, not the literal 0, because the property is mutable later in the same scope. Fix with a per-field as "GET" assertion or as const on the whole object/array to freeze every property to its literal type.
  • null/undefined: two real JS values with matching TS types. Behavior is gated by strictNullChecks — off, they're silently assignable to anything (bug-prone, not recommended); on, they must be narrowed before use, same mechanics as optional properties.
  • Non-null assertion (x!): postfix ! strips null/undefined from a type without a runtime check — use only when you're certain the value can't actually be nullish; wrong usage produces no error, just a runtime crash later.
  • enum is unusual among TS features: it's not purely type-level, it adds actual runtime code/values to JavaScript. Know it exists; the handbook explicitly suggests holding off using it unless you're sure you want it.
  • Less common primitives: bigint (ES2020+, arbitrary-precision integers, literal suffix 100n); symbol (globally unique reference via Symbol() — two calls with the same description are still distinct values, so firstName === secondName is always false and TS flags the comparison as an error).

Code Examples

function printId(id: number | string) {
  if (typeof id === "string") {
    console.log(id.toUpperCase()); // narrowed to string
  } else {
    console.log(id); // narrowed to number
  }
}
  • What it demonstrates: narrowing a union with a typeof check — the canonical way to work with a union member-specific API.
const req = { url: "https://example.com", method: "GET" } as const;
handleRequest(req.url, req.method); // method stays literal "GET", not widened to string
  • What it demonstrates: as const freezes every property to its literal type, avoiding the "widened to string" inference trap when passing object fields into a function expecting a literal union.

Reference Tables

FeatureSyntaxNotes
ArrayT[] or Array<T>equivalent
UnionA | Bvalue is one of the listed types
Optional propertykey?: Treads as T | undefined
Type assertionx as Tcompile-time only, no runtime check
Non-null assertionx!strips null | undefined, no runtime check
Freeze literal types{...} as constprevents literal-to-string/number widening

Key Takeaways

  1. Prefer interface by default for object shapes; switch to type when you need unions, tuples, or intersection composition.
  2. as/<T>/! are all compile-time-only — never rely on them for runtime safety; they can lie.
  3. When a literal-typed argument silently widens to string/number and breaks a call, reach for as const before scattering per-field assertions.
  4. Enable strictNullChecks — treating null/undefined as ordinary assignable values is a major, avoidable source of bugs.

Connects To

  • The Basics: strict/noImplicitAny/strictNullChecks flags referenced throughout this chapter.
  • Narrowing: the full set of techniques (not just typeof/Array.isArray) for narrowing unions.
  • Object Types: goes deeper on interfaces, readonly, index signatures, and generic object types.
  • Enums (reference): the dedicated chapter for the runtime-affecting enum feature mentioned here only in passing.