TypeScript Exercises and Examples

These TypeScript exercises combine the main ideas from this tutorial. Try to write the types yourself first, then compare with the solution. Paste the code into a TypeScript playground or a local .ts file and run it with npx tsx.

Exercise 1: Type a Product Catalog

Create a Product type with id, name, category (one of a fixed set) and price, then write a function that returns products in a category sorted by price.

type Category = "Grains" | "Beverages" | "Snacks";
type Product = { id: number; name: string; category: Category; price: number };

const catalog: Product[] = [
  { id: 1, name: "Basmati Rice", category: "Grains", price: 12.5 },
  { id: 2, name: "Green Tea", category: "Beverages", price: 6 },
  { id: 5, name: "Coffee Beans", category: "Beverages", price: 22 },
  { id: 4, name: "Dark Chocolate", category: "Snacks", price: 4.25 },
];

function byCategory(items: Product[], cat: Category): string[] {
  return items
    .filter((p) => p.category === cat)
    .toSorted((a, b) => a.price - b.price)
    .map((p) => `${p.name} (${p.price})`);
}
console.log(byCategory(catalog, "Beverages"));
[ 'Green Tea ($6)', 'Coffee Beans ($22)' ]

Exercise 2: A Generic groupBy

Write a generic function that groups any array by a key function and returns a Record of arrays.

function groupBy<T, K extends string>(items: T[], getKey: (item: T) => K): Record<K, T[]> {
  const out = {} as Record<K, T[]>;
  for (const item of items) {
    (out[getKey(item)] ??= []).push(item);
  }
  return out;
}

const words = ["apple", "avocado", "banana", "blueberry", "cherry"];
const grouped = groupBy(words, (w) => w[0]);
console.log(grouped);
{
  a: [ 'apple', 'avocado' ],
  b: [ 'banana', 'blueberry' ],
  c: [ 'cherry' ]
}

Exercise 3: Model a Request State

Use a discriminated union for idle, loading, success and error states, and an exhaustive switch to render each.

type State<T> =
  | { tag: "idle" }
  | { tag: "loading" }
  | { tag: "success"; data: T }
  | { tag: "error"; error: string };

function view(s: State<string[]>): string {
  switch (s.tag) {
    case "idle": return "Click to load";
    case "loading": return "Loading...";
    case "success": return s.data.join(", ");
    case "error": return "Oops: " + s.error;
    default: {
      const never: never = s;
      return never;
    }
  }
}
console.log(view({ tag: "success", data: ["Lahore", "Dubai"] }));
console.log(view({ tag: "error", error: "Network" }));
Lahore, Dubai
Oops: Network

Exercise 4: A Typed Event Emitter

Build a small event emitter whose event names and payloads are checked by the compiler.

type Events = {
  login: { user: string };
  logout: undefined;
};

class Emitter<E extends Record<string, unknown>> {
  #handlers: { [K in keyof E]?: ((payload: E[K]) => void)[] } = {};
  on<K extends keyof E>(name: K, fn: (payload: E[K]) => void) {
    (this.#handlers[name] ??= []).push(fn);
  }
  emit<K extends keyof E>(name: K, payload: E[K]) {
    this.#handlers[name]?.forEach((fn) => fn(payload));
  }
}

const bus = new Emitter<Events>();
bus.on("login", (p) => console.log("Welcome", p.user));
bus.emit("login", { user: "Naeem" });
// bus.emit("login", { name: "x" }); // Error: 'name' does not exist in type '{ user: string }'.
Welcome Naeem

More Ideas to Practice

  • Convert one of your JavaScript projects to TypeScript with strict mode on
  • Write a DeepReadonly<T> mapped type
  • Type a fetch helper that validates responses with a type guard
  • Create a typed shopping cart class with add, remove and total methods
  • Model a form with Partial and Record for field errors

Frequently asked questions

Where can I practice TypeScript online?

The official TypeScript Playground runs in the browser and shows errors and compiled JavaScript instantly. You can also run files locally with npx tsx.

How do I convert a JavaScript project to TypeScript?

Add a tsconfig.json with allowJs, rename files from .js to .ts one at a time, fix the errors, then enable strict mode once everything compiles.

What should I learn after TypeScript basics?

Use TypeScript with React or Node.js, learn runtime validation with Zod, and explore advanced types like conditional and mapped types.