Syntax
let name: string;
let age: number;
let isActive: boolean;Examples
Primitive Type Annotations
Explicitly typing variables with the core primitives.
let name: string = "Alice";
let age: number = 25;
let isActive: boolean = true;
// TypeScript catches mismatches immediately
// age = "twenty-five"; // Error: Type 'string' is not assignable to type 'number'
let id: string | number = 101; // union type, can be eitherany vs unknown
unknown is the type-safe alternative to any - it requires a check before you can use the value.
let flexible: any = "hello";
flexible.toUpperCase(); // allowed, no error - any disables checking entirely
flexible = 42; // also allowed, any accepts anything
let safer: unknown = "hello";
// safer.toUpperCase(); // Error - must narrow the type first
if (typeof safer === "string") {
safer.toUpperCase(); // OK now - TypeScript knows it is a string here
}void and never
Types for functions that return nothing, or never return at all.
function logMessage(message: string): void {
console.log(message); // no return statement - return type is void
}
function throwError(message: string): never {
throw new Error(message); // never actually returns - always throws
}
function infiniteLoop(): never {
while (true) { /* never exits */ }
}Best practices
- Prefer unknown over any whenever possible - it forces you to check a value's type before using it, catching bugs any would silently allow
- Let TypeScript infer types where it reasonably can (const age = 25) rather than annotating every single variable - annotate mainly function parameters and return types
- Use never for functions that always throw or never return, which helps TypeScript correctly narrow types in the code that calls them
- Avoid any as a habit - it is sometimes necessary for gradual migration or truly dynamic data, but it opts out of type safety entirely wherever it is used
At a glance
- Purpose
- Static types for JavaScript
- File extension
- .ts ยท .tsx
- Runs in
- Compiled to JavaScript
- Usually used with
- JavaScript and its ecosystem
Specifications & further reading
Related TypeScript documentation
Type Aliases
The type keyword creates a named alias for any type - not just object shapes like interface, but also unions, primitives, tuples, and function signatures. Type aliases make complex types reusable and give them a meaningful name, improving both readability and error messages.Union and Intersection Types
A union type (A | B) means a value can be either type A or type B. An intersection type (A & B) means a value must satisfy both A and B simultaneously, combining their members into one type. Unions are common for values with a few valid states; intersections are common for combining smaller, focused types into a larger one.Literal Types
Literal types narrow a type down to one specific, exact value rather than a general category - "success" instead of string, or 200 instead of number. They are most useful combined with union types, letting you precisely constrain a value to a specific set of allowed options, catching typos and invalid values at compile time.Type Inference
TypeScript can automatically determine a value's type from its initializer, without an explicit annotation - this is type inference. It reduces boilerplate significantly while still providing full type safety. Understanding what TypeScript infers (and when it needs help) is key to writing idiomatic, uncluttered TypeScript.
The type keyword creates a named alias for any type - not just object shapes like interface, but also unions, primitives, tuples, and function signatures. Type aliases make complex types reusable and give them a meaningful name, improving both readability and error messages.Union and Intersection Types
A union type (A | B) means a value can be either type A or type B. An intersection type (A & B) means a value must satisfy both A and B simultaneously, combining their members into one type. Unions are common for values with a few valid states; intersections are common for combining smaller, focused types into a larger one.Literal Types
Literal types narrow a type down to one specific, exact value rather than a general category - "success" instead of string, or 200 instead of number. They are most useful combined with union types, letting you precisely constrain a value to a specific set of allowed options, catching typos and invalid values at compile time.Type Inference
TypeScript can automatically determine a value's type from its initializer, without an explicit annotation - this is type inference. It reduces boilerplate significantly while still providing full type safety. Understanding what TypeScript infers (and when it needs help) is key to writing idiomatic, uncluttered TypeScript.