TypeScript Generics and Utility Types Interview Questions and Answers
15 questions on generics, constraints, keyof, mapped and conditional types, infer, and the built-in utility types.
Published October 24, 2026 · Updated October 29, 2026 · 15 questions
Edited by Dev Kilaru, Senior Data Analyst. How we make our content
1. What are generics, and why are they useful?
Generics let you write code that works with many types while keeping them related and checked. Instead of returning any, a generic function tells the compiler that the output type depends on the input type.
function first<T>(items: T[]): T | undefined { return items[0]; } const n = first([1, 2, 3]); // number | undefined const s = first(['a', 'b']); // string | undefined2. What are generic constraints?
The extends keyword limits which types are allowed for a type parameter, so you can safely use their members.
function longest<T extends { length: number }>(a: T, b: T): T { return a.length >= b.length ? a : b; }3. What does keyof do, and how is it combined with generics?
keyof T produces a union of the property names of T. Combined with a constraint it gives type-safe property access.
function getProp<T, K extends keyof T>(obj: T, key: K): T[K] { return obj[key]; } getProp({ id: 1, name: 'Ada' }, 'name'); // string4. What is typeof in a type position?
In type positions, typeof takes the type of a value, so you can derive types from existing objects instead of repeating them: type Config = typeof defaultConfig. It differs from the runtime typeof operator, which returns a string.
5. What are mapped types?
A mapped type builds a new type by transforming each property of another type. Many utility types are written this way. Modifiers can be added or removed with plus or minus signs.
type Optional<T> = { [K in keyof T]?: T[K] }; type Mutable<T> = { -readonly [K in keyof T]: T[K] };6. What are conditional types and the infer keyword?
A conditional type chooses between two types based on a check: T extends U ? X : Y. Inside the extends clause, infer captures part of a matched type into a new type variable.
type ElementOf<T> = T extends (infer U)[] ? U : never; type A = ElementOf<string[]>; // string type Unwrap<T> = T extends Promise<infer R> ? R : T;7. What are Partial, Required, and Readonly?
Partial<T> makes every property optional. Required<T> makes every property required. Readonly<T> makes every property readonly. They are shallow: nested objects are not changed.
8. What are Pick and Omit?
Pick<T, K> builds a type with only the listed keys. Omit<T, K> builds a type with everything except the listed keys.
interface User { id: number; name: string; email: string; } type PublicUser = Omit<User, 'email'>; type UserName = Pick<User, 'id' | 'name'>;9. What is Record, and when do you use it?
Record<K, V> describes an object whose keys are of type K and whose values are of type V. It is ideal for lookups keyed by a union of literals, because the compiler then requires every key to be present: Record<Status, string>.
10. What do ReturnType, Parameters, and Awaited do?
ReturnType<typeof fn> gives the return type of a function. Parameters<typeof fn> gives its parameter types as a tuple. Awaited<T> unwraps the type a promise resolves to, including nested promises. They let you derive types from existing code instead of duplicating them.
11. What do Exclude, Extract, and NonNullable do?
Exclude<T, U> removes from a union the members assignable to U. Extract<T, U> keeps only those members. NonNullable<T> removes null and undefined.
type T1 = Exclude<'a' | 'b' | 'c', 'a'>; // 'b' | 'c' type T2 = Extract<string | number, number>; // number12. What are template literal types?
They build string literal types from other types using template literal syntax, enabling precise strings such as event names or CSS classes. Unions inside the template expand into every combination.
type EventName = 'click' | 'hover'; type Handler = `on${Capitalize<EventName>}`; // 'onClick' | 'onHover'13. What is a default type parameter?
A type parameter can have a default used when none is supplied or inferred: interface ApiResponse<T = unknown> { data: T }. This keeps simple uses short while allowing precise types when needed.
14. What is variance, and what do covariance and contravariance mean?
Variance describes how subtyping of generic arguments carries over to the generic type. Return positions are covariant (a function returning Dog can be used where one returning Animal is expected). Parameter positions are contravariant when strictFunctionTypes is enabled (a function accepting Animal can be used where one accepting Dog is expected). Method shorthand is checked more loosely for historical reasons.
15. How would you type a function that returns a different type based on its argument?
Use overloads, or a generic with a conditional or lookup type. A lookup is often cleanest.
interface EventMap { click: MouseEvent; keydown: KeyboardEvent; } function listen<K extends keyof EventMap>( name: K, handler: (event: EventMap[K]) => void ): void { /* ... */ }
Interview Tips
- Build complex types step by step on the whiteboard rather than writing the final form at once.
- Know the common utility types well enough to write Partial and Pick from scratch.
- Keep generics readable: name type parameters meaningfully when there are more than one or two.