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.