TypeScript Programs
Practice Code Examples
Hands-on TypeScript programs to practice the type system. From basic annotations to advanced generic utilities.
TypeScript 5
✓ Practice
35 Programs
01
Basic Programs
#1Typed Function: Check PrimeBasic
TypeScript
function isPrime(n: number): boolean { if (n < 2) return false; for (let i = 2; i <= Math.sqrt(n); i++) if (n % i === 0) return false; return true; } isPrime(17); // true
#2Factorial with Type AnnotationBasic
TypeScript
const factorial = (n: number): number => n <= 1 ? 1 : n * factorial(n - 1); factorial(5); // 120
#3Reverse a StringBasic
TypeScript
const reverse = (s: string): string => s.split("").reverse().join(""); reverse("hello"); // "olleh"
#4Check PalindromeBasic
TypeScript
function isPalindrome(s: string): boolean { const c = s.toLowerCase().replace(/[^a-z0-9]/g, ""); return c === c.split("").reverse().join(""); } isPalindrome("Race car"); // true
#5Typed Object LiteralBasic
TypeScript
interface User { name: string; age: number; } const ada: User = { name: "Ada", age: 36 }; ada.name; // "Ada" — autocompleted & type-checked
#6Literal Union: Traffic LightBasic
TypeScript
type Light = "red" | "yellow" | "green"; const next: Record<Light, Light> = { red: "green", green: "yellow", yellow: "red", }; next["red"]; // "green"
#7Celsius to FahrenheitBasic
TypeScript
const toF = (c: number): number => c * 9 / 5 + 32; toF(100); // 212
#8Count VowelsBasic
TypeScript
const vowels = (s: string): number => (s.match(/[aeiou]/gi) ?? []).length; vowels("TypeScript"); // 2
#9FizzBuzz (typed)Basic
TypeScript
function fizzbuzz(n: number): string { if (n % 15 === 0) return "FizzBuzz"; if (n % 3 === 0) return "Fizz"; if (n % 5 === 0) return "Buzz"; return String(n); }
#10Sum a number[]Basic
TypeScript
const sum = (nums: number[]): number => nums.reduce((a, b) => a + b, 0); sum([1, 2, 3, 4]); // 10
#11Enum: Order StatusBasic
TypeScript
enum Status { Pending = "PENDING", Shipped = "SHIPPED" } let s: Status = Status.Pending; s === Status.Pending; // true
#12Optional Chaining + NullishBasic
TypeScript
interface Cfg { server?: { port?: number }; } const port = (c: Cfg): number => c.server?.port ?? 8080; port({}); // 8080
#13Tuple: Coordinate SwapBasic
TypeScript
const swap = ([a, b]: [number, number]): [number, number] => [b, a]; swap([1, 2]); // [2, 1]
02
Intermediate Programs
#14Generic first<T>Intermediate
TypeScript
function first<T>(arr: T[]): T | undefined { return arr[0]; } first(["a", "b"]); // string | undefined
#15Type Guard: isStringIntermediate
TypeScript
function isString(v: unknown): v is string { return typeof v === "string"; } const x: unknown = "hi"; if (isString(x)) x.trim(); // x is string here
#16Discriminated Union: AreaIntermediate
TypeScript
type Shape = | { kind: "circle"; r: number } | { kind: "square"; s: number }; const area = (sh: Shape): number => sh.kind === "circle" ? Math.PI * sh.r ** 2 : sh.s ** 2;
#17Generic groupByIntermediate
TypeScript
function groupBy<T>(arr: T[], key: (x: T) => string): Record<string, T[]> { return arr.reduce((acc, item) => { (acc[key(item)] ??= []).push(item); return acc; }, {} as Record<string, T[]>); }
#18keyof Property GetterIntermediate
TypeScript
function pluck<T, K extends keyof T>(arr: T[], key: K): T[K][] { return arr.map(x => x[key]); } pluck([{ id: 1 }, { id: 2 }], "id"); // number[]
#19Debounce (typed generic)Intermediate
TypeScript
function debounce<A extends unknown[]>( fn: (...args: A) => void, ms: number ): (...args: A) => void { let t: ReturnType<typeof setTimeout>; return (...args) => { clearTimeout(t); t = setTimeout(() => fn(...args), ms); }; }
#20Result<T, E> UnionIntermediate
TypeScript
type Result<T, E = Error> = | { ok: true; value: T } | { ok: false; error: E }; function divide(a: number, b: number): Result<number> { return b === 0 ? { ok: false, error: new Error("div by zero") } : { ok: true, value: a / b }; }
#21Word Frequency (Map)Intermediate
TypeScript
function freq(text: string): Map<string, number> { const m = new Map<string, number>(); for (const w of text.split(/\s+/)) m.set(w, (m.get(w) ?? 0) + 1); return m; }
#22Binary Search (generic-ish)Intermediate
TypeScript
function bsearch(a: number[], t: number): number { let lo = 0, hi = a.length - 1; while (lo <= hi) { const mid = (lo + hi) >>> 1; if (a[mid] === t) return mid; a[mid] < t ? (lo = mid + 1) : (hi = mid - 1); } return -1; }
#23Assert Never (exhaustive)Intermediate
TypeScript
function assertNever(x: never): never { throw new Error(`Unexpected: ${x}`); } // use in a switch default to force handling every case
#24Pick a Subset TypeIntermediate
TypeScript
interface User { id: string; name: string; pw: string; } type SafeUser = Omit<User, "pw">; const strip = ({ pw, ...rest }: User): SafeUser => rest;
03
Advanced Programs
#25Generic Stack<T>Advanced
TypeScript
class Stack<T> { private items: T[] = []; push(x: T): void { this.items.push(x); } pop(): T | undefined { return this.items.pop(); } get size(): number { return this.items.length; } }
#26Typed EventEmitterAdvanced
TypeScript
class Emitter<E extends Record<string, unknown[]>> { private m: { [K in keyof E]?: ((...a: E[K]) => void)[] } = {}; on<K extends keyof E>(e: K, fn: (...a: E[K]) => void) { (this.m[e] ??= []).push(fn); } emit<K extends keyof E>(e: K, ...a: E[K]) { this.m[e]?.forEach(fn => fn(...a)); } }
#27Memoize (generic)Advanced
TypeScript
function memoize<A extends unknown[], R>(fn: (...a: A) => R): (...a: A) => R { const cache = new Map<string, R>(); return (...a) => { const k = JSON.stringify(a); if (!cache.has(k)) cache.set(k, fn(...a)); return cache.get(k)!; }; }
#28DeepReadonly<T> Mapped TypeAdvanced
TypeScript
type DeepReadonly<T> = { readonly [K in keyof T]: T[K] extends object ? DeepReadonly<T[K]> : T[K]; }; // every nested property becomes readonly, recursively
#29Typed fetch WrapperAdvanced
TypeScript
async function getJson<T>(url: string): Promise<T> { const res = await fetch(url); if (!res.ok) throw new Error(`HTTP ${res.status}`); return res.json() as Promise<T>; } // const u = await getJson<User>("/api/me");
#30Builder Pattern (fluent, typed)Advanced
TypeScript
class Query { private parts: string[] = []; select(c: string): this { this.parts.push(`SELECT ${c}`); return this; } from(t: string): this { this.parts.push(`FROM ${t}`); return this; } build(): string { return this.parts.join(" "); } } new Query().select("*").from("users").build();
#31Merge Sort (typed generic)Advanced
TypeScript
function mergeSort<T>(a: T[], cmp: (x: T, y: T) => number): T[] { if (a.length <= 1) return a; const mid = a.length >> 1; const l = mergeSort(a.slice(0, mid), cmp); const r = mergeSort(a.slice(mid), cmp); const out: T[] = []; let i = 0, j = 0; while (i < l.length && j < r.length) out.push(cmp(l[i], r[j]) <= 0 ? l[i++] : r[j++]); return [...out, ...l.slice(i), ...r.slice(j)]; }
#32Branded Type (nominal)Advanced
TypeScript
type UserId = string & { __brand: "UserId" }; const toUserId = (s: string): UserId => s as UserId; // prevents mixing a UserId with a plain string at compile time
#33Awaited Return of a FnAdvanced
TypeScript
async function load() { return { id: 1 }; } type Loaded = Awaited<ReturnType<typeof load>>; // { id: number }
#34Pipe (variadic-ish compose)Advanced
TypeScript
const pipe = <T>(...fns: ((x: T) => T)[]) => (x: T): T => fns.reduce((acc, fn) => fn(acc), x); const f = pipe<number>(n => n + 1, n => n * 2); f(3); // 8
#35Type-Safe Object.entriesAdvanced
TypeScript
function entries<T extends object>(obj: T): [keyof T, T[keyof T]][] { return Object.entries(obj) as [keyof T, T[keyof T]][]; } entries({ a: 1, b: "x" }); // ["a"|"b", number|string][]