TypeScript Developer interview questions
100 real questions with model answers and explanations for TypeScript Developer candidates.
See a TypeScript Developer resume example →Practice with flashcards
Spaced repetition · Hunter Pass
Questions
A conditional type selects one type or another according to an assignability check written as T extends U ? X : Y.
- Distribution occurs when the checked side is a naked type parameter and that parameter receives a union.
- TypeScript evaluates each union member separately and unions the resulting branches.
- Wrapping both sides of the check in single-element tuples, such as [T] extends [U], suppresses distribution.
Why interviewers ask this: The interviewer is checking whether you understand both conditional type syntax and its most consequential union behavior.
I would define a distributive filter such as type StringMembers<T> = T extends string ? T : never.
- Each member of a union is tested independently because T is a naked type parameter.
- Matching members survive unchanged while nonmatching members become never.
- Since never disappears from a union, StringMembers<string | number | 'ready'> resolves to string.
Why interviewers ask this: A strong answer connects distributive conditional types with never rather than merely presenting memorized syntax.
A conditional type can remain unresolved while its checked type parameter is still unknown.
- The compiler cannot safely choose either branch until the generic is instantiated with a concrete type.
- Code inside the generic implementation may therefore need an assertion even when callers receive a precise conditional return type.
- Overload signatures can sometimes express the public relationship more cleanly while keeping the implementation broad.
Why interviewers ask this: The interviewer wants to see that you distinguish caller-facing type precision from what can be proven inside a generic implementation.
Nested conditional types form an ordered decision tree in which each false branch performs the next check.
- The order matters when conditions overlap because the first matching branch wins.
- Extracting named helper types keeps a long chain readable and exposes reusable concepts.
- If the cases represent runtime states, a discriminated union is often clearer than encoding every decision only at the type level.
Why interviewers ask this: The question tests whether you can use conditional types without turning them into an unreadable substitute for domain modeling.
In conditional types, never commonly represents a rejected case and acts as a filter for union members.
- A union containing never simplifies by removing it, so accepted members remain.
- A conditional applied directly to never may itself resolve to never because distributive evaluation has no members to process.
- Tuple wrapping is useful when never must be detected as a value of the type computation rather than distributed away.
Why interviewers ask this: The interviewer is evaluating whether you understand never as both an impossible type and an algebraic tool in type transformations.
I would disable distribution by comparing tuple-wrapped types, for example [T] extends [Allowed] ? Yes : No.
- The tuple makes the checked side something other than a naked type parameter.
- TypeScript then tests the complete union against Allowed in one assignability operation.
- This distinction matters for all-or-nothing validation such as requiring every event payload to satisfy a shared contract.
Why interviewers ask this: A strong answer explains why tuple wrapping changes semantics and gives a reason to prefer whole-union evaluation.
A recursive conditional type can exceed TypeScript's instantiation depth or make editor checks noticeably slower.
- Every recursive step creates more type instantiations, and unions can multiply that work through distribution.
- A depth parameter represented by a tuple counter can provide an explicit stopping condition.
- I keep recursive utilities narrow and measure compiler diagnostics before adopting them in widely imported libraries.
Why interviewers ask this: The interviewer is checking whether your type-level knowledge includes compiler cost and safe termination, not only expressiveness.
I would first require T to extend readonly unknown[] and then test whether number extends T['length'].
- General arrays have length typed as number, so the check succeeds for them.
- Tuples expose a finite union of numeric length literals, so number does not extend that length type.
- Supporting readonly arrays prevents the utility from rejecting tuples inferred through as const.
Why interviewers ask this: This tests whether you can combine conditional types with indexed access and understand how tuple metadata differs from array metadata.
A mapped type creates properties by iterating over a union of PropertyKey values, commonly keyof another type.
- The iterator variable represents one key at a time and can index the source type to preserve each property's value type.
- Mapping over keyof T retains the relationship between each source key and T[K].
- Modifiers and key remapping let the transformation change optionality, mutability, or property names.
Why interviewers ask this: The interviewer is assessing whether you see mapped types as key-driven transformations rather than generic object syntax.
Mapped types use readonly and ? modifiers, with + to add them and - to remove them.
- The plus sign is implicit, so readonly [K in keyof T] and +readonly [K in keyof T] are equivalent.
- Writing -readonly or -? produces mutable or required versions of the mapped properties.
- These transformations affect compile-time assignability and do not freeze objects or fill missing values at runtime.
Why interviewers ask this: A strong answer covers modifier syntax and avoids confusing static property constraints with runtime behavior.
The as clause computes a new key for each source key while the mapped type still reads values from the original key.
- Template literal types can rename keys, such as converting name into getName.
- Producing never from the as clause removes that property from the result.
- Non-string keys often need a constraint such as K extends string before applying string transformations.
Why interviewers ask this: The interviewer wants to see that you can rename and filter properties while preserving the source value relationship.
I would remap each key to itself when T[K] matches the target type and to never otherwise.
- A shape such as { [K in keyof T as T[K] extends V ? K : never]: T[K] } performs both filtering and reconstruction.
- Optional properties may include undefined, so the match policy must state whether to use T[K] or NonNullable<T[K]>.
- The test is based on assignability, which can include literal subtypes and unions depending on distribution.
Why interviewers ask this: This question checks whether you can combine indexed access, conditionals, and key remapping with deliberate optional-property semantics.
Mapping over keyof T transforms an existing shape, while mapping over an arbitrary string union constructs a shape from an independent key set.
- With keyof T, T[K] is valid and preserves each original property's value type.
- With independent keys, the value type must come from another rule because those keys need not exist on T.
- Record<K, V> is the standard utility for the second pattern when every selected key shares one value type.
Why interviewers ask this: The interviewer is testing whether you understand the source of keys and values in mapped object construction.
A homomorphic mapped type iterates over keyof T and lets TypeScript preserve structural details from the source properties.
- It naturally carries optional and readonly modifiers unless the mapping explicitly changes them.
- The value expression T[K] maintains the exact association between every key and its value type.
- Replacing the key set or remapping keys can stop some of that preservation because the result is no longer a direct copy transformation.
Why interviewers ask this: A strong answer recognizes why common utilities retain source modifiers and when that behavior can be lost.
I would recursively map object properties to readonly while treating functions and primitive values as terminal cases.
- Arrays and tuples need deliberate handling so tuple positions are preserved instead of collapsing into a broad array type.
- Built-ins such as Date, Map, and Set require an explicit policy because recursively mapping their methods does not make their internal state immutable.
- The type only prevents mutations accepted by the compiler and does not perform runtime freezing.
Why interviewers ask this: The interviewer is evaluating recursive mapped type design, edge-case awareness, and the boundary between static and runtime immutability.
Partial<T> is appropriate when every property of T is independently optional, such as a simple patch object.
- It does not express dependencies between fields or require at least one field to be present.
- Applying it to a domain entity can admit invalid intermediate objects that no runtime operation supports.
- For constrained updates I define a dedicated input type or combine Pick with a union of allowed update shapes.
Why interviewers ask this: The interviewer wants evidence that you use Partial intentionally rather than as a shortcut around domain rules.
Pick defines an allowlist of properties, while Omit starts with the full type and removes a denylist.
- Pick is safer for narrow public contracts because newly added source properties do not appear automatically.
- Omit is convenient when the result should track almost the entire source type, but source additions can silently widen the exposed shape.
- For security-sensitive DTOs I prefer an explicit Pick or a dedicated interface over excluding known secrets.
Why interviewers ask this: A strong answer goes beyond syntax and considers how source type evolution affects public contracts.
Record<K, V> requires a value of type V for every key in the finite key union K.
- Record<'idle' | 'ready', Handler> reports a missing handler for either named state.
- A string index signature describes values for arbitrary string keys and cannot normally require a particular finite set by itself.
- With noUncheckedIndexedAccess, reading an open dictionary can include undefined, while a complete finite Record has known keys.
Why interviewers ask this: The interviewer is checking whether you can choose between exhaustive finite maps and open-ended dictionaries.
Required<T> removes the optional modifier from every top-level property of T.
- It does not recursively require nested optional fields unless a separate deep utility is used.
- It does not validate runtime input or create values for fields that are missing.
- Under strict null checks, a required property may still allow undefined if undefined is explicitly part of its declared value type.
Why interviewers ask this: The question tests whether you understand the exact scope of Required and the difference between presence and value unions.
I would intersect the original type with Required<Pick<T, K>>, often simplifying the displayed result through a mapped identity type.
- Pick isolates the selected keys and Required removes their optional modifiers.
- The intersection preserves all unselected properties with their original value types and modifiers.
- A reusable helper should constrain K to keyof T so invalid property names fail at the call site.
Why interviewers ask this: The interviewer is evaluating whether you can compose standard utilities instead of reimplementing their behavior.
Locked questions
- 21
Why is Omit<T, K> structurally permissive when K contains keys that are not in T?
- 22
How do Exclude and Extract differ from Pick and Omit?
- 23
What are template literal types useful for beyond representing formatted strings?
typesadvanced-types - 24
How do unions behave inside multiple interpolations of a template literal type?
typesadvanced-typesunion - 25
How would you type an event listener whose event name determines the callback value type?
callbacks - 26
What do the intrinsic string manipulation types Uppercase, Lowercase, Capitalize, and Uncapitalize do?
- 27
Can a template literal type enforce that a runtime string is a valid route?
typesadvanced-types - 28
How can infer decompose a string inside a template literal type?
typesadvanced-types - 29
What makes a union discriminated, and why is that better than several optional fields?
uniontypes - 30
How do you enforce exhaustive handling of a discriminated union?
uniontype-narrowing - 31
How would you model asynchronous request state with a discriminated union?
asynctype-narrowingunion - 32
Why can destructuring break or weaken narrowing of a discriminated union?
destructuringtype-narrowingunion - 33
How can Extract help retrieve one variant from a discriminated union?
uniontype-narrowing - 34
When should two related dimensions be one discriminated union rather than separate unions?
uniontype-narrowing - 35
What is the difference between a built-in type guard and a user-defined type predicate?
type-narrowing - 36
How would you safely narrow an unknown value to a domain object?
- 37
When should a guard return asserts value is T instead of value is T?
- 38
Why does Array.filter sometimes preserve a narrowed element type and sometimes not?
- 39
What are the limitations of instanceof as a type guard?
type-narrowing - 40
How does the in operator narrow a union, and what subtlety do optional properties introduce?
uniontypes - 41
What is the purpose of a .d.ts file, and what belongs in it?
- 42
What is the difference between an ambient module declaration and module augmentation?
- 43
How do declare global and global .d.ts scripts differ from normal external modules?
- 44
What should you verify when publishing declaration files for a TypeScript library?
typescriptdeclarations - 45
What should you consider before using decorators in TypeScript?
typescriptdecorators - 46
Why can a method decorator that wraps a function accidentally break behavior or typing?
decorators - 47
How do keyof, typeof, and indexed access work together to derive types from a value?
advanced-typesindexes - 48
Why does T[keyof T] produce a value union, and when can it be too broad?
unionadvanced-types - 49
What does infer do inside a conditional type?
advanced-types - 50
How would you recursively unwrap nested Promise types with infer?
promisesrecursionadvanced-types - 51
How would you type an API client when the server response cannot be trusted?
api - 52
How would you model an endpoint that can return data, validation issues, or an authorization failure?
authvalidationendpoints - 53
How would you type an API client whose endpoints have different parameters and response types?
endpoints - 54
How would you type a sorting utility so callers can sort only by comparable object fields?
algorithms - 55
How would you design an update helper that never permits changing id or createdAt?
design - 56
You receive a long TS2322 error involving several generics; how do you debug it?
generics - 57
An empty array becomes never[] in a generic workflow; how do you fix it?
generics - 58
Function overloads work for callers but the implementation has type errors; what do you check?
- 59
A union of callbacks loses its relationship with payload types; how would you preserve it?
unioncallbacks - 60
A generic helper accepts object and needs assertions internally; how would you improve it?
generics - 61
How would you preserve literal route names while checking a configuration object shape?
config - 62
How would you implement a type-safe event emitter for a known event map?
type-safety - 63
How would you stop frontend form values and backend validation types from drifting?
formsvalidationiac - 64
How would you type parameters for /users/:userId/posts/:postId?
generics - 65
How would you type a repository without pretending every entity supports identical operations?
- 66
A polymorphic component accepts an as prop; how would you keep its props type-safe?
componentstype-safety - 67
A package has no TypeScript declarations; how would you type it?
typescript - 68
Third-party declarations omit a real runtime method; how would you fix the type locally?
dependencies - 69
How would you expose a safe wrapper around an untyped vendor SDK?
procurement - 70
How do you ensure a published TypeScript library ships correct declarations?
typescript - 71
A dual ESM and CommonJS library resolves wrong types; how do you debug it?
modules - 72
How would you introduce TypeScript clients generated from OpenAPI?
openapitypescript - 73
How would you keep GraphQL operation types accurate?
graphql - 74
How would you refactor a module that uses any throughout without stopping feature work?
refactoring - 75
How would you enable strictNullChecks in a mature codebase with thousands of errors?
- 76
Several boolean flags permit impossible workflow states; how would you refactor them?
refactoring - 77
How would you prevent mixing UserId and OrderId when both are strings?
- 78
How would you type serialization when domain objects contain Date, Map, or branded values?
serialization - 79
Object.keys loses specific key types; how do you handle this in a utility?
soft-skills - 80
A reduce accumulator has no expected properties; how do you fix its typing?
- 81
How would you preserve result types for several different promises passed to a helper?
promises - 82
How would you type expected failures in an asynchronous service method?
async - 83
How do you make a union switch fail when a new case is added?
union - 84
How would you write a custom type guard for localStorage data?
type-narrowing - 85
How would you type a factory that accepts a class constructor?
- 86
How would you type dependency injection tokens when interfaces vanish at runtime?
injectiontokenstypes - 87
Middleware adds user to context but handlers cannot see it; how do you type the flow?
middleware - 88
How would you type environment variables so missing configuration fails early?
config - 89
How would you derive a type-safe feature flag API from configuration?
configfeature-flagsapi - 90
A team wants nested property path types; how would you keep them maintainable?
- 91
Would you use DeepPartial for test fixtures, and how would you limit its risks?
fixtures - 92
How would you type a cache where each key has a different value type?
caching - 93
How would you type a command bus so each command reaches the right handler?
- 94
How would you type state transitions so events cannot run from the wrong state?
- 95
How would you type debounce without losing the wrapped function parameters?
debounce - 96
Inference breaks in a generic compose helper; how would you approach it?
genericsadvanced-types - 97
How would you type a data table so each accessor matches its cell renderer?
- 98
How would you type an SDK method that follows paginated API responses?
api - 99
The compiler reports excessively deep type instantiation; how do you debug it?
- 100
A dependency upgrade creates hundreds of type errors; how do you investigate?
dependencies