Click any item to expand the explanation and examples.
📦 Basic Types
Primitive Types basics
let name: string = "Alice";
let age: number = 30;
let active: boolean = true;
let data: null = null;
let value: undefined = undefined;
let id: bigint = 100n;
let key: symbol = Symbol("key");
Arrays & Tuples basics
let nums: number[] = [1, 2, 3]; let names: Array<string> = ["Alice", "Bob"];// Tuple: fixed length and types let pair: [string, number] = [“age”, 30]; let rgb: [number, number, number] = [255, 128, 0];
// Readonly tuple let point: readonly [number, number] = [10, 20];
any / unknown / never / void basics
let x: any = "anything"; // opt out of type checking let y: unknown = "safe any"; // must narrow before usePreferfunction log(msg: string): void { // no return value console.log(msg); }
function fail(msg: string): never { // never returns throw new Error(msg); }
unknown over any — it forces you to check the type before using it.
🏗️ Interfaces & Type Aliases
interface types
interface User {
id: number;
name: string;
email: string;
age?: number; // optional
readonly createdAt: Date; // can't reassign
}
// Extend
interface Admin extends User {
role: “admin” | “superadmin”;
}
// Method signatures
interface API {
getUser(id: number): Promise<User>;
deleteUser(id: number): Promise<void>;
}
type alias types
type ID = string | number;
type Status = "active" | "inactive" | "pending";
type Point = { x: number; y: number };
type Callback = (data: string) => void;
// Intersection (combine types)
type Admin = User & { role: string };
Use interface for object shapes, type for unions, intersections, and primitives.
🔀 Union & Intersection Types
Union Types (A | B) unions
type ID = string | number;function printId(id: ID) { if (typeof id === “string”) { console.log(id.toUpperCase()); // narrowed to string } else { console.log(id.toFixed(2)); // narrowed to number } }
// Literal unions type Direction = “up” | “down” | “left” | “right”; type HttpStatus = 200 | 301 | 404 | 500;
Intersection Types (A & B) unions
type HasName = { name: string };
type HasAge = { age: number };
type Person = HasName & HasAge;
const p: Person = { name: “Alice”, age: 30 };
Discriminated Unions unions
type Circle = { kind: "circle"; radius: number };
type Square = { kind: "square"; side: number };
type Shape = Circle | Square;
function area(shape: Shape): number {
switch (shape.kind) {
case “circle”: return Math.PI * shape.radius ** 2;
case “square”: return shape.side ** 2;
}
}
🧬 Generics
Generic Functions generics
function identity<T>(value: T): T {
return value;
}
identity<string>(“hello”); // explicit
identity(42); // inferred as number
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
Generic Constraints generics
function getLength<T extends { length: number }>(item: T): number {
return item.length;
}
getLength(“hello”); // 5
getLength([1, 2, 3]); // 3
// getLength(42); // Error: number has no .length
// keyof constraint
function getProperty<T, K extends keyof T>(obj: T, key: K): T[K] {
return obj[key];
}
Generic Interfaces & Types generics
interface ApiResponse<T> {
data: T;
status: number;
message: string;
}
type Result<T, E = Error> =
| { ok: true; value: T }
| { ok: false; error: E };
const res: ApiResponse<User[]> = {
data: [{ id: 1, name: “Alice”, email: “a@b.c”, createdAt: new Date() }],
status: 200,
message: “OK”
};
🛠️ Utility Types
Partial<T> / Required<T> utility
interface User {
name: string;
email: string;
age: number;
}
type UpdateUser = Partial<User>;
// { name?: string; email?: string; age?: number }
type StrictUser = Required<User>;
// all properties required, even if originally optional
Pick<T, K> / Omit<T, K> utility
type UserPreview = Pick<User, "name" | "email">;
// { name: string; email: string }
type UserWithoutAge = Omit<User, “age”>;
// { name: string; email: string }
Record<K, V> utility
type Roles = "admin" | "user" | "guest";
type Permissions = Record<Roles, boolean>;
// { admin: boolean; user: boolean; guest: boolean }
const cache: Record<string, number> = {};
cache[“hits”] = 42;
Readonly<T> utility
type FrozenUser = Readonly<User>;const user: FrozenUser = { name: “Alice”, email: “a@b.c”, age: 30 }; // user.name = “Bob”; // Error: readonly
// Also works with arrays const nums: ReadonlyArray<number> = [1, 2, 3]; // nums.push(4); // Error
Exclude / Extract / NonNullable utility
type T = "a" | "b" | "c";type WithoutA = Exclude<T, “a”>; // “b” | “c” type OnlyAB = Extract<T, “a” | “b”>; // “a” | “b”
type Maybe = string | null | undefined; type Sure = NonNullable<Maybe>; // string
ReturnType / Parameters utility
function createUser(name: string, age: number) {
return { name, age, id: Math.random() };
}
type NewUser = ReturnType<typeof createUser>;
// { name: string; age: number; id: number }
type Args = Parameters<typeof createUser>;
// [name: string, age: number]
🔒 Enums
Enums enums
const enum or literal unions for most cases.
enum Direction {
Up = "UP",
Down = "DOWN",
Left = "LEFT",
Right = "RIGHT",
}
const move = Direction.Up; // “UP”
// Numeric enum (auto-increments)
enum Status {
Active, // 0
Inactive, // 1
Pending, // 2
}
// Prefer literal unions in most cases:
type Direction = “UP” | “DOWN” | “LEFT” | “RIGHT”;
🛡️ Type Guards & Assertions
Type Guards guards
// typeof
if (typeof value === "string") { /* string here */ }
// instanceof
if (error instanceof TypeError) { /* TypeError here */ }
// in operator
if (“email” in user) { /* has email property */ }
// Custom type guard
function isUser(obj: unknown): obj is User {
return typeof obj === “object” && obj !== null && “name” in obj;
}
if (isUser(data)) {
console.log(data.name); // safely narrowed
}
Type Assertions guards
const input = document.getElementById("name") as HTMLInputElement;
input.value = "Alice";
// Alternative syntax
const el = <HTMLInputElement>document.getElementById(“name”);
// Non-null assertion (!)
const el = document.getElementById(“name”)!; // assert not null
Assertions don’t do runtime checks — they just tell the compiler to trust you.
🧪 Advanced Types
Mapped Types advanced
// Make all properties optional (this is how Partial works)
type MyPartial<T> = {
[K in keyof T]?: T[K];
};
// Make all properties nullable
type Nullable<T> = {
[K in keyof T]: T[K] | null;
};
// Readonly (this is how Readonly works)
type MyReadonly<T> = {
readonly [K in keyof T]: T[K];
};
Conditional Types advanced
type IsString<T> = T extends string ? "yes" : "no";type A = IsString<string>; // “yes” type B = IsString<number>; // “no”
// Practical: extract array element type type ElementOf<T> = T extends (infer E)[] ? E : never; type X = ElementOf<string[]>; // string
Template Literal Types advanced
type Color = "red" | "blue";
type Size = "sm" | "lg";
type ClassName = `${Size}-${Color}`;
// "sm-red" | "sm-blue" | "lg-red" | "lg-blue"
type EventName = on${Capitalize<string>};
// “onClick”, “onHover”, etc.
type Getter<T extends string> = get${Capitalize<T>};
type NameGetter = Getter<“name”>; // “getName”
Quick Reference Table
| Feature | Syntax |
|---|---|
| String type | let s: string = "hi" |
| Array | let a: number[] = [1, 2] |
| Tuple | let t: [string, number] |
| Interface | interface User { name: string } |
| Type alias | type ID = string | number |
| Union | string | number |
| Intersection | TypeA & TypeB |
| Generic | function fn<T>(x: T): T |
| Partial | Partial<User> |
| Pick | Pick<User, "name"> |
| Omit | Omit<User, "age"> |
| Record | Record<string, number> |
| Readonly | Readonly<User> |
| Type guard | if (typeof x === "string") |
| Assertion | value as Type |
| Mapped type | { [K in keyof T]: ... } |
| Conditional | T extends U ? A : B |
| Template literal | `${A}-${B}` |