TypeScript Basic Types
TypeScript's type system is built on a foundation of basic types that correspond to JavaScript's runtime types while adding static type checking. Understanding these fundamental types is essential for effective TypeScript development and forms the basis for more advanced type features.
The basic types in TypeScript include primitive types like string
, number
, and boolean
, as well as more complex types like arrays, objects, and functions. Each type provides compile-time guarantees about the shape and behavior of your data, helping catch errors before they reach production.
Primitive Types
TypeScript includes several primitive types that correspond directly to JavaScript's primitive values.
String Type represents textual data:
let message: string = "Hello, TypeScript!";
let name: string = 'John Doe';
let template: string = `Welcome, ${name}`;
// String methods are fully typed
let upperMessage: string = message.toUpperCase();
let messageLength: number = message.length;
Number Type represents both integers and floating-point numbers:
let age: number = 25;
let price: number = 99.99;
let binary: number = 0b1010;
let octal: number = 0o744;
let hexadecimal: number = 0xf00d;
// Mathematical operations are type-safe
let total: number = price * 2;
let isEven: boolean = age % 2 === 0;
Boolean Type represents true/false values:
let isActive: boolean = true;
let isComplete: boolean = false;
let hasPermission: boolean = age >= 18;
// Boolean logic is fully supported
let canProceed: boolean = isActive && hasPermission;
BigInt Type for arbitrarily large integers:
let bigNumber: bigint = 100n;
let anotherBig: bigint = BigInt(9007199254740991);
// BigInt operations
let sum: bigint = bigNumber + anotherBig;
Symbol Type for unique identifiers:
let sym1: symbol = Symbol();
let sym2: symbol = Symbol("key");
let sym3: symbol = Symbol.for("global");
// Symbols are always unique
console.log(sym1 === sym2); // false
Null and Undefined
TypeScript treats null
and undefined
as distinct types, which helps catch common errors.
let nullable: null = null;
let undefinedValue: undefined = undefined;
// These can be part of union types
let maybeString: string | null = null;
let optionalNumber: number | undefined = undefined;
// Strict null checks help prevent runtime errors
function processValue(value: string | null): string {
if (value === null) {
return "No value provided";
}
return value.toUpperCase(); // TypeScript knows value is string here
}
Arrays
TypeScript provides multiple ways to define array types, ensuring type safety for collection operations.
Array Syntax using square brackets:
let numbers: number[] = [1, 2, 3, 4, 5];
let strings: string[] = ["hello", "world"];
let booleans: boolean[] = [true, false, true];
// Array methods are fully typed
let doubled: number[] = numbers.map(n => n * 2);
let found: number | undefined = numbers.find(n => n > 3);
Generic Array Type using Array<T>
:
let fruits: Array<string> = ["apple", "banana", "orange"];
let scores: Array<number> = [95, 87, 92];
// Mixed types require union types
let mixed: Array<string | number> = ["hello", 42, "world"];
Readonly Arrays prevent modification:
let readonlyNumbers: readonly number[] = [1, 2, 3];
let readonlyStrings: ReadonlyArray<string> = ["a", "b", "c"];
// These operations would cause compile errors:
// readonlyNumbers.push(4);
// readonlyNumbers[0] = 10;
Tuples
Tuples represent arrays with a fixed number of elements of specific types in specific positions.
// Basic tuple
let person: [string, number] = ["Alice", 30];
let coordinate: [number, number] = [10, 20];
// Accessing tuple elements
let name: string = person[0];
let age: number = person[1];
// Optional tuple elements
let optionalTuple: [string, number?] = ["Bob"];
let withOptional: [string, number?] = ["Charlie", 25];
// Rest elements in tuples
let variableTuple: [string, ...number[]] = ["scores", 95, 87, 92];
// Named tuple elements (TypeScript 4.0+)
let namedTuple: [name: string, age: number] = ["David", 35];
Object Types
Objects can be typed using interface-like syntax or type aliases.
Inline Object Types:
let user: { name: string; age: number; email: string } = {
name: "John",
age: 30,
email: "[email protected]"
};
// Optional properties
let config: { host: string; port?: number } = {
host: "localhost"
};
// Readonly properties
let point: { readonly x: number; readonly y: number } = {
x: 10,
y: 20
};
Index Signatures for dynamic property names:
let dictionary: { [key: string]: string } = {
hello: "world",
foo: "bar"
};
let numberMap: { [key: string]: number } = {
age: 30,
score: 95
};
Function Types
Functions can have their parameters and return types explicitly typed.
// Function declaration with types
function add(a: number, b: number): number {
return a + b;
}
// Function expression with types
let multiply = (x: number, y: number): number => {
return x * y;
};
// Optional parameters
function greet(name: string, greeting?: string): string {
return `${greeting || "Hello"}, ${name}!`;
}
// Default parameters
function createUser(name: string, age: number = 18): object {
return { name, age };
}
// Rest parameters
function sum(...numbers: number[]): number {
return numbers.reduce((total, num) => total + num, 0);
}
Type Annotations vs Type Inference
TypeScript can often infer types automatically, but explicit annotations provide clarity and catch errors.
Type Inference:
let message = "Hello"; // TypeScript infers string
let count = 42; // TypeScript infers number
let items = [1, 2, 3]; // TypeScript infers number[]
// Function return type inference
function double(x: number) {
return x * 2; // Return type inferred as number
}
Explicit Type Annotations:
let message: string = "Hello"; // Explicit annotation
let count: number = 42; // Explicit annotation
let items: number[] = [1, 2, 3]; // Explicit annotation
// Explicit return type
function double(x: number): number {
return x * 2;
}
Any and Unknown Types
These types provide escape hatches for the type system with different levels of safety.
Any Type disables type checking:
let anything: any = 42;
anything = "hello";
anything = true;
anything.foo.bar; // No type checking
// Use sparingly, defeats purpose of TypeScript
Unknown Type is the type-safe counterpart to any:
let userInput: unknown = getUserInput();
// Must check type before using
if (typeof userInput === "string") {
console.log(userInput.toUpperCase());
}
if (typeof userInput === "number") {
console.log(userInput.toFixed(2));
}
Void and Never Types
These types represent the absence of values in different contexts.
Void Type for functions that don't return a value:
function logMessage(message: string): void {
console.log(message);
// No return statement
}
function processData(data: any[]): void {
data.forEach(item => console.log(item));
return; // Can return undefined
}
Never Type for functions that never return:
function throwError(message: string): never {
throw new Error(message);
}
function infiniteLoop(): never {
while (true) {
// Never terminates
}
}
// Never is useful in exhaustive checks
function handleValue(value: string | number): string {
if (typeof value === "string") {
return value.toUpperCase();
}
if (typeof value === "number") {
return value.toString();
}
// This should never be reached
const exhaustiveCheck: never = value;
return exhaustiveCheck;
}
Understanding these basic types is crucial for TypeScript development. They provide the foundation for creating type-safe applications and enable TypeScript's powerful features like type inference, compile-time error checking, and excellent IDE support. As you become comfortable with these basics, you'll be ready to explore more advanced TypeScript features like interfaces, generics, and utility types.