Basic Types and Annotations
Annotate variables and function signatures with primitive types, arrays, and objects — the vocabulary of every TypeScript file.
Every TypeScript file builds on the same primitive vocabulary JavaScript uses at runtime — string, number, boolean, null, undefined — plus compile-time helpers like void and never that describe control flow rather than stored values. Annotations attach those names to variables, parameters, and return positions so tsc and your editor agree on what may exist. You are not learning a new data model; you are naming shapes the engine already understands.
Primitive annotations and return types
Primitive annotations document intent at the declaration site. When you write let price: number, you tell the compiler every reassignment must stay numeric — no accidental string concatenation from a form field. void marks functions that run for side effects only; never marks functions that cannot return normally because they throw or loop forever. These types erase at compile time but guide every call site during development.
AceDevHubArrays, readonly, and tuples
Array types describe homogeneous collections where every element shares the same type. TypeScript offers two equivalent syntaxes — string[] and Array<string> — with identical checking behavior. When you need a fixed-length collection with different types at each index, tuples express that constraint. Readonly arrays prevent accidental mutation through push or splice at compile time, which matters for shared configuration and constant lookup tables passed between modules.
Inference often picks readonly string[] when you use as const on a literal array. Explicit annotations widen or narrow that behavior depending on whether you plan to mutate. For function returns that pair related values — like data plus HTTP status — a named tuple [data: T, status: number] documents intent better than a generic object with two fields.
Object types and structural typing
TypeScript uses structural typing: compatibility depends on shape, not class names. Optional properties use ? and may be undefined when absent. Excess property checking on object literals catches typos like naem instead of name at assignment time.
any vs unknown — two escape hatches
any disables type checking — loose.foo.bar() compiles even when unsafe. unknown is the type-safe top type: assign anything, but narrow before reading properties. Use unknown for JSON.parse results and external input until validated.
1| Type | Use without narrowing? | When to use |
|---|---|---|
| any | Yes | Legacy migration only |
| unknown | No | External input until validated |
| never | N/A | Exhaustive checks, throw helpers |
Putting primitives together
Real modules combine primitives, arrays, and object shapes at boundaries. Export typed configuration, accept User in handlers, return void from log helpers. Name the shape once, reuse everywhere data flows.
- Annotate when inference is too wide
- Use tuples for fixed-length returns
- Choose unknown over any for external data
- 1Primitives mirror JS runtime types plus void and never
- 2Structural object types document fields
- 3Next lesson: type inference vs explicit annotations