Basic Types, Inference, and Annotations
Learn primitive types, arrays, tuples, literals, inference, and how to annotate values without over-annotating.
Primitive Types
The everyday primitive types are string, number, boolean, bigint, symbol, and the special types null and undefined (with nullability behavior governed by compiler options). Use lowercase type names such as string, not the JavaScript wrapper object type String.
TypeScript also supports void for functions whose return value is not intended to be used, never for values that cannot occur, and object for non-primitive values. Avoid Object as a broad type because it does not express a useful data contract.
const username: string = "Mira";
const retryCount: number = 3;
const isEnabled: boolean = true;
function logMessage(message: string): void {
console.log(message);
}- Use lowercase primitive type names.
voiddescribes an intentionally unused return value.- Avoid broad wrapper types such as
StringandObject.
Which is the recommended TypeScript primitive type annotation?
Type Inference
Type inference lets the compiler derive a type from a value or expression. If you write const count = 3, TypeScript knows count is the literal type 3 in many contexts; a let variable is usually widened to number because it can be reassigned. Inference reduces noise while preserving checks.
Annotate when a type is not obvious, when you want a stable public contract, or when inference would be too narrow or too broad. Function parameter types generally need annotations unless contextual typing supplies them, such as in callbacks passed to typed APIs.
const appName = "Bytes4Dev";
let requestCount = 0;
const names = ["Asha", "Ravi"].map((name) => name.toUpperCase());
// name is inferred as string; names is string[]appName, requestCount, the array element type, and the callback parameter. Contextual typing supplies name: string from map's array signature.- Inference often makes explicit annotations unnecessary.
- Use annotations to clarify contracts, not to repeat every inferred type.
- Contextual typing provides types from the surrounding API.
What does TypeScript generally do when a callback is passed to a well-typed `map` call?
Arrays, Tuples, and Literal Types
Use T[] or Array<T> for arrays whose elements share a type. A tuple describes a fixed positional structure, such as [number, string]; optional and rest elements can model more flexible tuples. Literal types restrict values to specific strings, numbers, booleans, or unique symbols, and are often used for modes and discriminants.
as const preserves literal values and makes object properties and arrays readonly at the type level. It does not freeze the object at runtime. Prefer unions of literal values over a generic string when only a small known set is valid.
const scores: number[] = [82, 91, 76];
const userRecord: [id: number, name: string] = [7, "Mira"];
type Theme = "light" | "dark" | "system";
const theme: Theme = "dark";scores is an array of numbers, userRecord has two typed positions, and Theme permits only the three declared strings.- Arrays describe repeated values; tuples describe positions.
- Literal unions constrain a value to known alternatives.
as constaffects compile-time inference, not runtime immutability.
Which type best models a value that can only be `"small"`, `"medium"`, or `"large"`?