Skip to main content

TypeScript Exercises

This document contains 30 practice exercises for TypeScript. Each exercise includes:

  • Starting JavaScript code.
  • A Hint pointing to the TypeScript feature to use and its purpose.
  • A hidden solution inside <details> for self-paced learning.

Difficulty increases progressively.


Exercise 1: Simple Addition (Basic Types)

// Convert to TypeScript
function add(a, b) {
return a + b;
}

Hint: Use number type for parameters and return value.

💡 View solution
function add(a: number, b: number): number {
return a + b;
}

Exercise 2: Optional and Default Parameters

// Convert to TypeScript
function greet(name, greeting) {
greeting = greeting || "Hello";
return `${greeting}, ${name}`;
}

Hint: Use default parameter syntax greeting: string = "Hello".

💡 View solution
function greet(name: string, greeting: string = "Hello"): string {
return `${greeting}, ${name}`;
}

Exercise 3: Defining an Object with an Interface

// Convert to TypeScript
const createUser = (u) => {
return `User ${u.name} created with id ${u.id}`;
};

Hint: Use an interface to define the shape of User.

💡 View solution
interface User {
id: number;
name: string;
email?: string; // optional
}

const createUser = (u: User): string => {
return `User ${u.name} created with id ${u.id}`;
};

Exercise 4: Readonly and Literal Types

// Convert to TypeScript
const config = {
mode: "production",
version: "1.0.0"
};

Hint: Use readonly properties and union literals "development" | "production".

💡 View solution
type Mode = "development" | "production" | "test";

interface Config {
readonly mode: Mode;
readonly version: string;
}

const config: Config = {
mode: "production",
version: "1.0.0"
};

Exercise 5: Tuples

// Convert to TypeScript
function createPair(name, age) {
return [name, age];
}

Hint: Use a tuple type [string, number].

💡 View solution
function createPair(name: string, age: number): [string, number] {
return [name, age];
}

Exercise 6: Enums for Statuses

// Convert to TypeScript
const status = "Active"; // can be 'Active' or 'Inactive'

Hint: Use enum Status.

💡 View solution
enum Status {
Active = "Active",
Inactive = "Inactive"
}

const currentStatus: Status = Status.Active;

Exercise 7: Generics Identity

// Convert to TypeScript
function identity(x) {
return x;
}

Hint: Use <T> generic parameter.

💡 View solution
function identity<T>(x: T): T {
return x;
}

const num = identity<number>(123);
const str = identity("hello");

Exercise 8: Generic Constraints

// Convert to TypeScript
function getLength(x) {
return x.length;
}

Hint: Use T extends { length: number }.

💡 View solution
function getLength<T extends { length: number }>(x: T): number {
return x.length;
}

console.log(getLength('hello')); // 4
console.log(getLength([1,2,3])); // 3

Exercise 9: Union Types and Type Narrowing

// Convert to TypeScript
function format(x) {
if (typeof x === 'number') {
return x.toFixed(2);
}
return x.trim();
}

Hint: Use x: string | number and typeof.

💡 View solution
function format(x: string | number): string {
if (typeof x === 'number') {
return x.toFixed(2);
}
return x.trim();
}

Exercise 10: Discriminated Unions

// Convert to TypeScript
function area(shape) {
if (shape.kind === 'circle') {
return Math.PI * shape.radius * shape.radius;
}
return shape.size * shape.size;
}

Hint: Define circle and square types with a kind discriminant property.

💡 View solution
type Circle = { kind: 'circle'; radius: number };
type Square = { kind: 'square'; size: number };
type Shape = Circle | Square;

function area(shape: Shape): number {
if (shape.kind === 'circle') {
return Math.PI * shape.radius * shape.radius;
}
return shape.size * shape.size;
}

Exercise 11: Utility Types: Pick and Omit

// Convert to TypeScript
const user = { id: 1, name: 'Ana', password: '123' };
// We want a public user type without password

Hint: Use Omit<User, 'password'> or Pick<User, 'id' | 'name'>.

💡 View solution
interface User {
id: number;
name: string;
password: string;
}

type PublicUser = Omit<User, 'password'>;

const safeUser: PublicUser = { id: 1, name: 'Ana' };

Exercise 12: Utility Types: Partial and Required

// Convert to TypeScript
function update(user, changes) {
return { ...user, ...changes };
}

Hint: Use Partial<User> for changes.

💡 View solution
interface User {
id: number;
name: string;
email?: string;
}

function update(user: User, changes: Partial<User>): User {
return { ...user, ...changes };
}

Exercise 13: Promises and Async/Await

// Convert to TypeScript
async function fetchUser() {
const r = await fetch('/user');
return r.json();
}

Hint: Annotate return type as Promise<User>.

💡 View solution
interface User { id: number; name: string; }

async function fetchUser(): Promise<User> {
const r = await fetch('/user');
const data = await r.json() as User;
return data;
}