Skip to content

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

typescriptadvanced-typesunion

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.

unionadvanced-types

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.

genericsadvanced-types

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.

advanced-types

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.

advanced-types

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.

uniontesting

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.

recursionconcurrencyadvanced-types

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.

typesadvanced-types

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.

iterationadvanced-types

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.

advanced-typestypes

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.

advanced-types

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.

advanced-types

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.

unionadvanced-types

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.

advanced-types

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.

design

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.

designapi

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.

indexes

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.

types

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.

rest

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