Capítulo 2 de 36
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.
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.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.let x: string, not string x), and are almost always optional — TypeScript infers from initializers.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>..forEach((s) => ...) infers s from the array's element type) — no annotation needed.{ x: number; y: number }; property separator can be , or ;; an unannotated property is implicitly any.last?: string): reading one gives T | undefined — must narrow (obj.last !== undefined) or use ?. before use.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 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.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)."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.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.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.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).function printId(id: number | string) {
if (typeof id === "string") {
console.log(id.toUpperCase()); // narrowed to string
} else {
console.log(id); // narrowed to number
}
}
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
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.| Feature | Syntax | Notes |
|---|---|---|
| Array | T[] or Array<T> | equivalent |
| Union | A | B | value is one of the listed types |
| Optional property | key?: T | reads as T | undefined |
| Type assertion | x as T | compile-time only, no runtime check |
| Non-null assertion | x! | strips null | undefined, no runtime check |
| Freeze literal types | {...} as const | prevents literal-to-string/number widening |
interface by default for object shapes; switch to type when you need unions, tuples, or intersection composition.as/<T>/! are all compile-time-only — never rely on them for runtime safety; they can lie.string/number and breaks a call, reach for as const before scattering per-field assertions.strictNullChecks — treating null/undefined as ordinary assignable values is a major, avoidable source of bugs.strict/noImplicitAny/strictNullChecks flags referenced throughout this chapter.typeof/Array.isArray) for narrowing unions.enum feature mentioned here only in passing.