Basic Types
TypeScript Programming
Basic Types in TypeScript
TypeScript provides a rich set of basic types that map to JavaScript's runtime types while adding compile-time safety. Understanding these foundational types is essential because every variable, parameter, and return value in a well-typed TypeScript program carries a type annotation. The compiler uses these annotations to verify that values are used consistently throughout your code, eliminating entire categories of bugs before they reach users.
Primitive Types
TypeScript's primitive types mirror JavaScript's: string, number, and boolean. Unlike some languages that distinguish between integers and floating-point numbers, TypeScript (like JavaScript) has a single number type that covers both.
// String type
let firstName: string = "Alice";
let greeting: string = `Hello, ${firstName}`;
// Number type — integers and floats alike
let age: number = 30;
let price: number = 19.99;
let hex: number = 0xff;
let binary: number = 0b1010;
// Boolean type
let isActive: boolean = true;
let hasPermission: boolean = false;
The any Type
The any type opts out of type checking entirely. A variable of type any can hold any value and can be assigned to any other variable without compiler complaints. While useful during migration from JavaScript, overusing any defeats the purpose of TypeScript. Prefer unknown when you genuinely do not know the type — it is safer because it forces you to narrow the type before using the value.
let flexible: any = "hello";
flexible = 42; // no error
flexible = true; // no error
flexible.foo.bar; // no error (but will crash at runtime!)
// unknown is safer — must narrow before use
let safe: unknown = getData();
if (typeof safe === "string") {
console.log(safe.toUpperCase()); // OK after narrowing
}
void, null, and undefined
The void type represents the absence of a return value and is most commonly used as the return type of functions that do not return anything. The types null and undefined each have their own type with the same name. When strictNullChecks is enabled (recommended), null and undefined are not assignable to other types unless explicitly included in a union.
// void — function returns nothing
function logMessage(msg: string): void {
console.log(msg);
// no return statement
}
// null and undefined as types
let nothing: null = null;
let notAssigned: undefined = undefined;
// With strictNullChecks, this is an error:
// let name: string = null; // Error!
// Use a union to allow null
let name: string | null = null;
name = "Alice"; // OK
never and bigint
The never type represents values that never occur — for example, a function that always throws an error or has an infinite loop. The bigint type handles arbitrarily large integers when number is not sufficient.
// never — function that never returns
function throwError(message: string): never {
throw new Error(message);
}
// bigint — for very large integers
let huge: bigint = 9007199254740991n;
let alsoHuge: bigint = BigInt("9007199254740991");
Type Inference
TypeScript can infer types from assigned values, so you do not always need explicit annotations. However, explicit annotations improve readability and catch mistakes at the point of declaration rather than at the point of use.
// Inferred as string — no annotation needed
let city = "Paris";
// Inferred as number
let count = 0;
// Explicit is clearer for function signatures
function add(a: number, b: number): number {
return a + b;
}
Tip: Let TypeScript infer local variable types when the value makes the type obvious. Always annotate function parameters and return types explicitly for clarity and safety.
Key Takeaways
string,number, andbooleanare the core primitive types in TypeScript.- Avoid
anywhenever possible; preferunknownfor truly unknown types. voidis used for functions that return nothing;neveris for functions that never return.- Enable
strictNullChecksand use union types likestring | nullto handle nullable values safely. - TypeScript infers types when possible, but explicit annotations on function signatures are best practice.