Skip to main content
Version: v1.4

✏️ 3.2.4.2 Whiteboard Practice: TypeScript II

Whiteboard Practice


When and how whiteboarding practice is implemented will be up to your teacher. Below are recommended prompts.

Note to Fidgetech Students: Contact your instructor when you read this lesson to set up a whiteboarding practice session.

Goal

For this whiteboarding session, you'll practice working with utility types, generics, and discriminated unions.

As the interviewee:

  • Ask clarifying questions.
  • Keep talking.
  • Explain your plan at the beginning; recap what you've done at the end.
  • Plan your space.

As the interviewer:

  • Answer questions as best as you can.
  • Be encouraging. Whiteboarding is difficult!
  • Be patient. Only offer hints if your partner indicates that they need help.
  • Be engaged. Part of this practice is getting used to having someone evaluate your work as you produce it.
  • Offer constructive feedback. Find at least one thing that your partner did well and one thing they could improve at.

Alternate who is whiteboarding between problems.


Problem 1

Given this type:

type Employee = {
id: number;
name: string;
department: string;
salary: number;
manager?: Employee;
};

Write a function getReportChain(employee: Employee): string[] that returns an array of names from the given employee up to the top of the management chain (the person with no manager). What type narrowing is needed?


Problem 2

Write a function mergeDefaults<T>(partial: Partial<T>, defaults: T): T that returns a complete T object. Properties present in partial should override the defaults; any that are missing should be filled in from defaults.

For example:

type AppConfig = {
theme: "light" | "dark";
language: string;
notificationsEnabled: boolean;
};

const defaults: AppConfig = {
theme: "light",
language: "en",
notificationsEnabled: true,
};

const userConfig: Partial<AppConfig> = {
theme: "dark",
};

mergeDefaults(userConfig, defaults);
// { theme: "dark", language: "en", notificationsEnabled: true }

What should the implementation look like? Can you use spread syntax here?


Problem 3

You have a function that fetches data from an API. It might succeed or fail:

type Result<T> =
| { success: true; data: T }
| { success: false; error: string };

Write a function fetchUser(id: number): Result<User> (you can simulate it with hardcoded data). Then write a function handleResult<T>(result: Result<T>, onSuccess: (data: T) => void, onError: (error: string) => void): void that calls the appropriate callback.

What type narrowing strategy is needed here?


Problem 4

Write a generic pipeline<T> function that takes an initial value of type T and an array of transformation functions, each of type (value: T) => T, and applies them in order, returning the final result.

For example:

const result = pipeline(
" hello world ",
[
s => s.trim(),
s => s.toUpperCase(),
s => s.replace(" ", "_"),
]
);
// "HELLO_WORLD"