TypeScript Programming Labs

Master Object-Oriented Programming with classes, enums, and powerful utility types in TypeScript.

OOP & Utility Types - Module 3

Learn classes with access modifiers, enums, and TypeScript's built-in utility types.

Lab 7: Classes & Object-Oriented Programming
Intermediate
Coding Challenge
Your Task: Master TypeScript classes with access modifiers, inheritance, and abstract classes. Classes are blueprints for creating objects with properties and methods.

Detailed Requirements:
1. Create a basic class with constructor: Create a Person class with properties name and age. Use the constructor shorthand:
class Person { constructor( public name: string, public age: number ) {} greet(): string { return "Hello, I'm " + this.name; } }

2. Use access modifiers: TypeScript has three access modifiers:
   • public - accessible everywhere (default)
   • private - only accessible within the class
   • protected - accessible within class and subclasses

Create a BankAccount class with a private balance and public methods to deposit/withdraw:
class BankAccount { private balance: number = 0; deposit(amount: number): void { this.balance += amount; } getBalance(): number { return this.balance; } }

3. Implement inheritance: Create an Employee class that extends Person. Add an employeeId property and override the greet method using super:
class Employee extends Person { constructor(name: string, age: number, public employeeId: string) { super(name, age); // Call parent constructor } greet(): string { return super.greet() + " (Employee #" + this.employeeId + ")"; } }

4. Create an abstract class: Abstract classes cannot be instantiated directly - they're templates for other classes:
abstract class Shape { abstract getArea(): number; // Must be implemented by subclasses describe(): string { return "Area: " + this.getArea(); } }

5. Implement the abstract class: Create Circle and Rectangle classes that extend Shape and implement getArea().

Expected Output:
Person: Hello, I'm Alice Account balance: $150 Employee: Hello, I'm Bob (Employee #E001) Circle area: 78.54 Rectangle area: 24 Shape description: Area: 78.54

Requirements Checklist

Create Person class with constructor and greet method
Create BankAccount with private balance
Create Employee class extending Person
Create abstract Shape class
Implement Circle and Rectangle extending Shape
Test all classes with console.log
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Constructor shorthand: constructor(public name: string) {}
• Private property: private balance: number = 0;
• Inheritance: class Employee extends Person { }
• Call parent: super(name, age) in constructor, super.method() for methods
• Abstract: abstract class Shape { abstract getArea(): number; }
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 8: Enums
Intermediate
Coding Challenge
Your Task: Master TypeScript enums - a way to define a set of named constants. Enums make code more readable and prevent invalid values.

Detailed Requirements:
1. Create a numeric enum: By default, enums start at 0 and auto-increment:
enum Direction { North, // 0 South, // 1 East, // 2 West // 3 } let heading: Direction = Direction.North; console.log(heading); // Output: 0

2. Create an enum with custom values: You can assign specific numbers:
enum HttpStatus { OK = 200, BadRequest = 400, Unauthorized = 401, NotFound = 404, InternalError = 500 }

3. Create a string enum: String enums have explicit string values (more readable in output/debugging):
enum Color { Red = "RED", Green = "GREEN", Blue = "BLUE" } let favorite: Color = Color.Blue; console.log(favorite); // Output: "BLUE"

4. Create a UserRole enum: Create a string enum with values "ADMIN", "EDITOR", "VIEWER".

5. Use enums in a function: Create a function getStatusMessage that takes an HttpStatus and returns an appropriate message using a switch statement:
function getStatusMessage(status: HttpStatus): string { switch (status) { case HttpStatus.OK: return "Success!"; case HttpStatus.NotFound: return "Resource not found"; // ... etc } }

6. Reverse mapping (numeric enums only): Get the name from a value:
console.log(Direction[0]); // "North" console.log(HttpStatus[404]); // "NotFound"

Why Enums?
• Self-documenting code
• IDE autocomplete for valid values
• Compile-time checking prevents typos
• Group related constants together

Expected Output:
Direction North: 0 Direction name from 2: East HTTP 200: Success! HTTP 404: Resource not found Color: BLUE User role: ADMIN Is admin: true

Requirements Checklist

Create Direction numeric enum (North, South, East, West)
Create HttpStatus enum with custom values (200, 400, 404, 500)
Create Color string enum (RED, GREEN, BLUE)
Create UserRole string enum (ADMIN, EDITOR, VIEWER)
Create getStatusMessage function with switch
Test enums and reverse mapping with console.log
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Numeric enum: enum Direction { North, South, East, West }
• Custom values: enum Status { OK = 200, NotFound = 404 }
• String enum: enum Color { Red = "RED" }
• Use enum: let dir: Direction = Direction.North;
• Reverse map: Direction[0] returns "North"
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below

Lab 9: Utility Types
Advanced
Coding Challenge
Your Task: Master TypeScript's built-in utility types that help you transform types. These are incredibly powerful for working with existing types.

Detailed Requirements:
1. Partial<T>: Makes all properties optional. Perfect for update functions where you might only change some fields:
interface User { id: number; name: string; email: string; } // All properties become optional type PartialUser = Partial<User>; // Same as: { id?: number; name?: string; email?: string; } function updateUser(user: User, updates: Partial<User>): User { return { ...user, ...updates }; }

2. Required<T>: Makes all properties required (opposite of Partial):
interface Config { host?: string; port?: number; } type RequiredConfig = Required<Config>; // Now host and port are both required

3. Readonly<T>: Makes all properties readonly (immutable):
type ReadonlyUser = Readonly<User>; const user: ReadonlyUser = { id: 1, name: "Alice", email: "a@b.com" }; // user.name = "Bob"; // ERROR: Cannot assign to 'name'

4. Pick<T, K>: Creates a type with only the specified properties:
type UserPreview = Pick<User, "id" | "name">; // Same as: { id: number; name: string; }

5. Omit<T, K>: Creates a type excluding the specified properties:
type UserWithoutEmail = Omit<User, "email">; // Same as: { id: number; name: string; }

6. Record<K, V>: Creates an object type with keys K and values V:
type UserRoles = Record<string, boolean>; const roles: UserRoles = { admin: true, editor: false };

Why Utility Types?
• Avoid duplicating type definitions
• Transform existing types safely
• Create precise types for specific use cases

Expected Output:
Original: { id: 1, name: "Alice", email: "alice@test.com" } Updated: { id: 1, name: "Alice Updated", email: "alice@test.com" } User preview (Pick): { id: 1, name: "Alice" } Without email (Omit): { id: 1, name: "Alice" } Roles record: { admin: true, editor: false, viewer: true }

Requirements Checklist

Create User interface and use Partial for updates
Use Required to make optional Config required
Use Readonly to create immutable type
Use Pick to select specific properties
Use Omit to exclude properties
Use Record and test all with console.log
Output
// Click "Run Code" to compile and execute
Hints & Tips
• Partial: type PartialUser = Partial<User>; makes all props optional
• Required: type RequiredConfig = Required<Config>;
• Readonly: type ImmutableUser = Readonly<User>;
• Pick: type Preview = Pick<User, "id" | "name">;
• Omit: type NoEmail = Omit<User, "email">;
• Record: type Dict = Record<string, number>;
Progress: 0/6
Score: 0/100
0%

Lab Results

Review feedback below