TypeScript's type system starts with a small set of primitive types: number, string, boolean, null, undefined, symbol, and bigint. These primitives serve as the building blocks for typing variables, function parameters, and return values. To annotate a variable's type explicitly, you place a colon and the type after the variable name, as in let name: string = "Alice";. Explicit annotations improve readability and prevent unintended type mismatches.
TypeScript also performs type inference: when a variable is initialized with a value, the compiler automatically infers its type from that initializer. Writing let count = 5; causes TypeScript to treat count as a number, eliminating the need for redundant annotations while still preserving type safety. Inference reduces boilerplate, but explicit annotations remain valuable wherever clarity or contract enforcement matters.
The type system includes a few special escape-hatch types. The any type disables type checking entirely, letting a value be treated as if it could be any type; it should be used sparingly because it bypasses the safety TypeScript exists to provide. The unknown type is a safer top type, requiring a type check or narrowing before any operation is performed on the value, which prevents accidental misuse. Finally, the never type represents values that never occur, such as the result of a function that always throws or the unreachable branch of an exhaustive switch statement.