Implementing Utility Types
TL;DR
Implementing the built-in utility types from scratch is the most common TypeScript interview question. It proves you understand Generics, the keyof operator, Mapped Types, and Conditional Types.
1. Implementing Partial<T>
Goal: Make all properties of T optional.
Mechanism: Use a mapped type to loop over keyof T and append the ? modifier.
type MyPartial<T> = {
[P in keyof T]?: T[P];
};
2. Implementing Readonly<T>
Goal: Make all properties of T readonly.
Mechanism: Use a mapped type and append the readonly modifier.
type MyReadonly<T> = {
readonly [P in keyof T]: T[P];
};
3. Implementing Pick<T, K>
Goal: Extract a set of properties K from T.
Mechanism: Ensure K is constrained to the keys of T (K extends keyof T). Loop over K and assign the original value.
type MyPick<T, K extends keyof T> = {
[P in K]: T[P];
};
4. Implementing Record<K, T>
Goal: Create an object with keys K and values T.
Mechanism: Keys must be valid object keys (PropertyKey is an alias for string | number | symbol). Loop over K.
type MyRecord<K extends PropertyKey, T> = {
[P in K]: T;
};
5. Implementing Exclude<T, U>
Goal: Exclude types from a union.
Mechanism: Use Conditional Types. If T extends U, return never (delete it), else keep T. Because it’s a conditional type operating on a union, it inherently distributes over the union.
type MyExclude<T, U> = T extends U ? never : T;
6. Implementing Omit<T, K>
Goal: Remove properties K from object T.
Mechanism: This is just a combination of Pick and Exclude. We Pick all keys from T that are not in K.
// Using our custom types from above!
type MyOmit<T, K extends PropertyKey> = MyPick<T, MyExclude<keyof T, K>>;
Common Interview Questions
Why does Omit not constrain K extends keyof T?
You’ll notice Pick strictly forces K to be a key of T. Omit in standard TypeScript intentionally does not do this. It allows you to omit a key that doesn’t even exist on the object without throwing an error (which aligns with JavaScript’s loose nature).