TypeScript

TypeScript Types

Master TypeScript's type system — primitives, unions, intersections, type aliases, and advanced utility types.

Basic Types

TypeScript adds static types to JavaScript. This catches errors at compile time rather than runtime, making your code more reliable.

// Primitive types
const name: string = "Alice";
const age: number = 25;
const isActive: boolean = true;
const value: null = null;
const nothing: undefined = undefined;
const bigNum: bigint = 9007199254740991n;

// Arrays
const numbers: number[] = [1, 2, 3];
const names: Array<string> = ["Alice", "Bob"];

// Tuples - fixed length arrays with specific types
const point: [number, number] = [10, 20];
const entry: [string, number] = ["Alice", 25];

// Object types inline
const user: { name: string; age: number; email?: string } = {
  name: "Alice",
  age: 25,
};

// Union types - either/or
type ID = string | number;
let userId: ID = "user-123";
userId = 456; // Also valid

// Literal types
type Direction = "north" | "south" | "east" | "west";
type StatusCode = 200 | 201 | 400 | 404 | 500;

const dir: Direction = "north";
// const invalid: Direction = "up"; // Error!

// Type assertions
const input = document.getElementById("myInput") as HTMLInputElement;

Union & Intersection Types

Union types represent values that can be one of several types. Intersection types combine multiple types into one.

// Union type: value is one OR the other
type StringOrNumber = string | number;
type NullableString = string | null | undefined;

// Discriminated unions - powerful pattern for exhaustive checks
type Shape =
  | { kind: 'circle'; radius: number }
  | { kind: 'rectangle'; width: number; height: number }
  | { kind: 'triangle'; base: number; height: number };

function getArea(shape: Shape): number {
  switch (shape.kind) {
    case 'circle':
      return Math.PI * shape.radius ** 2;
    case 'rectangle':
      return shape.width * shape.height;
    case 'triangle':
      return (shape.base * shape.height) / 2;
    // TypeScript knows all cases are handled
  }
}

// Intersection type: value has ALL properties
type Serializable = { serialize(): string };
type Loggable = { log(msg: string): void };

type SerializableAndLoggable = Serializable & Loggable;

// Combining object types
type BaseUser = { id: string; email: string };
type AdminUser = BaseUser & {
  role: 'admin';
  permissions: string[];
};

const admin: AdminUser = {
  id: "1",
  email: "admin@example.com",
  role: "admin",
  permissions: ["read", "write", "delete"],
};

Utility Types

TypeScript provides built-in utility types that transform existing types. These are incredibly useful for building type-safe applications.

interface User {
  id: string;
  name: string;
  email: string;
  password: string;
  createdAt: Date;
  updatedAt: Date;
}

// Partial - all properties optional
type UserUpdate = Partial<User>;
// { id?: string; name?: string; email?: string; ... }

// Required - all properties required
type RequiredUser = Required<UserUpdate>;

// Pick - select subset of properties
type UserPublic = Pick<User, 'id' | 'name' | 'email'>;
// { id: string; name: string; email: string }

// Omit - exclude specific properties
type UserWithoutPassword = Omit<User, 'password'>;

// Readonly - all properties read-only
type ImmutableUser = Readonly<User>;

// Record - key/value map
type UserRoles = Record<string, 'admin' | 'editor' | 'viewer'>;
const roles: UserRoles = {
  alice: 'admin',
  bob: 'editor',
};

// ReturnType & Parameters
async function fetchUser(id: string): Promise<User> { /* ... */ return {} as User; }

type FetchUserReturn = Awaited<ReturnType<typeof fetchUser>>; // User
type FetchUserParams = Parameters<typeof fetchUser>; // [string]

// Extract & Exclude
type OnlyString = Extract<string | number | boolean, string>; // string
type NotString = Exclude<string | number | boolean, string>; // number | boolean

Utility types are your best friend for DRY type definitions. Instead of duplicating interfaces, derive them from existing ones.