01 · Fundamentals
- annotations
- primitive types
- explicit vs implicit
- arrays string[] / number[]
- fixed tuples
End of the TypeScript Course
Congratulations! You have completed all 5 modules of the TypeScript Course — from basic type annotations and primitive types to robust programming with Interfaces, Unions, highly versatile Generics, Classes/Utility Types, and Advanced Types/Guards. Below is a map of what you have mastered and a five-step final challenge.
Reminder: TypeScript exercises are verified statically (keywords). To actually run the code, each exercise provides a TypeScript Playground button that copies the code and opens typescriptlang.org/play.
Combine what you have learned about TypeScript by building five small logical components: a generic array element retriever, an employee data helper with optional fields, an API response handler using discriminated unions, a task management system using classes/utility types, and a dashboard permission manager using custom type guards.
Write a generic function that accepts an array of elements of type T and returns the first element (or undefined if the array is empty). Module 3 (Generics).
Define the generic function firstElement<T>(arr: T[]): T | undefined that returns the first element of the array.
Use the generic signature <T> before parameters. The function should return arr[0] or undefined.
Solution available after 3 attempts
Define an Employee interface with an optional salary field, and a getSalary function that returns the salary or 0 if it is not specified. Module 2 (Interfaces and optional fields).
Create the Employee interface with id (number), name (string), and salary (optional number). Write getSalary(emp: Employee): number to check if salary is defined before returning it.
Use the question mark salary?: number in the interface and the nullish coalescing operator (??) in the function.
Solution available after 3 attempts
Define a type to handle an API response that can be either a success (with generic data) or a failure (with a string message). Module 2 (Unions and Narrowing) + Module 3 (Generics).
Create ApiResponse<T> as a union of Success<T> (status: "success", data: T) and Failure (status: "error", message: string). Write handleResponse<T>(res: ApiResponse<T>): string that checks res.status and returns either "Data: " + res.data or "Error: " + res.message.
Check res.status === "success" to narrow down the union type at runtime.
Solution available after 3 attempts
Define a NewTask type alias that omits id and completed from an existing Task interface, and implement a TaskManager class that manages a private array of Tasks. Module 4 (Classes and Utility Types).
Define the NewTask type by omitting id and completed from Task. Create the TaskManager class implementing ITaskManager, managing a private tasks array and a nextId counter starting from 1 to assign sequential IDs in the addTask method.
Use type NewTask = Omit<Task, "id" | "completed">; to exclude the keys. In the class, define private tasks: Task[] = []; and private nextId: number = 1;.
Solution available after 3 attempts
Define a NormalUser or Admin type with discriminated unions. Write a custom type guard isAdmin and a getDashboardAccess function to return a specific access string depending on the user role. Module 5 (Advanced Types and Guards).
Define the type guard isAdmin(user: User): user is Admin that checks if user.role === "admin". Then write the function getDashboardAccess(user: User): string that uses the isAdmin guard to return "Admin Access: " + user.permissions.join(", ") for admins, or "Standard Access for " + user.username for standard users.
Use function isAdmin(user: User): user is Admin { return user.role === "admin"; }. In the getDashboardAccess function, use an if block to test isAdmin(user) before accessing the permissions property.
Solution available after 3 attempts
A single page with all the essential syntax of modern TypeScript, ready to keep handy while you code.
Consistent practice is the best way to strengthen your skills. Open the TypeScript Playground to experiment freely with complex scenarios or to prepare your code snippets before testing them in your actual projects.