TypeScript Interview Questions – Practice Quiz for All Levels
Reviewed by Mark Dickie · Last updated
TypeScript is a statically typed superset of JavaScript that compiles to plain JavaScript and adds optional type annotations, interfaces, and compile-time checks to the language. For an interview, you should be comfortable with the structural type system, the difference between type aliases and interface declarations, how generics work, and where TypeScript's type narrowing kicks in at runtime boundaries. Questions at mid-to-senior level tend to focus on generics, utility types (Partial, Required, Pick, ReturnType, and friends), and conditional or mapped types. Understanding how tsconfig.json flags like strict, noUncheckedIndexedAccess, and moduleResolution affect a codebase will separate you from candidates who only know the basics.
What interviewers actually test
Interviews rarely stop at "what is a type vs an interface." The questions probe whether you can reason about TypeScript's type system under real conditions: narrowing inside control flow, dealing with unknown vs any, and writing generic utilities that stay type-safe at the call site.
Difficulty breakdown
| Level | Typical topics |
|-------|----------------|
| 1 – Beginner | Primitive types, interface vs type, any vs unknown, basic type annotations |
| 2 – Elementary | Union and intersection types, optional chaining, enums, basic generics |
| 3 – Intermediate | Utility types, type guards, as const, index signatures, readonly |
| 4 – Advanced | Conditional types, mapped types, infer, template literal types, declaration merging |
| 5 – Expert | Variance, higher-kinded type patterns, module augmentation, compiler internals |
Core areas to review before your interview
- Type system fundamentals — structural (duck) typing, literal types, type widening, and narrowing via
typeof,instanceof, and discriminated unions. - Generics — writing generic functions and classes, adding constraints with
extends, and usinginferinside conditional types. - Utility types — know the built-ins (
Partial,Required,Readonly,Pick,Omit,Exclude,Extract,ReturnType,Parameters) and be ready to re-implement one from scratch. - Configuration — how
strictmode bundlesstrictNullChecks,strictFunctionTypes, and others, and whynoImplicitAnymatters at a team level. - Interop patterns — typing third-party JavaScript with
.d.tsfiles, using@types/*packages, and handlingunknownat API boundaries.
TypeScript 5.x introduced const type parameters, variadic tuple improvements, and the satisfies operator. If the role uses a modern toolchain, expect at least one question on satisfies and why it differs from a plain type assertion.
At a glance
| Questions | 15 |
|---|---|
| Difficulty | 2–4 of 5 |
| Formats | Multiple choice, Multiple answer, True / false, Code output, Find the bug, Short answer, Flashcard |
What you'll review
- primitives
- union intersection
- partial required
- interface vs type
- exhaustiveness
- generic functions
- typeof instanceof
- type guards
- discriminated unions
- mapped types
- pick omit
- arrays tuples
- literal types
- returntype parameters
- template literal types
Practice questions
TypeScript/types-basics/primitives
How does unknown differ from any?
Options
unknownrequires narrowing before use;anydisables type checking entirely- They are interchangeable aliases
unknowncan be assigned to any other type without a checkanymust be narrowed before use;unknowncannot
Show answer
unknown requires you to narrow it before use, whereas any disables type checking entirely. Anything is assignable to unknown, but the compiler forces a check (like typeof) before you can operate on the value. any opts out of checking in both directions, so it silently lets unsafe operations through.
Anything is assignable to unknown, but you must narrow it before doing anything with it — it is the type-safe counterpart to any, which opts out of checking in both directions.
TypeScript/types-basics/union-intersection
Given type A = { x: number } and type B = A & { y: string }, what is B?
Options
- { x: number; y: string }
- { x: number } | { y: string }
- { y: string }
- never
Show answer
B is { x: number; y: string }. The & operator forms an intersection, so a value of type B must satisfy both A and { y: string } at once. That means it carries every property from both — the x: number from A and the y: string added on top.
& is an intersection: a value of type B must satisfy both A and { y: string }, so it has both x and y.
TypeScript/utility-types/partial-required
Which of these are built-in TypeScript utility types?
Options
- Partial<T>
- Pick<T, K>
- Maybe<T>
- Readonly<T>
Show answer
Partial<T>, Pick<T, K>, and Readonly<T> are all built-in utility types — but Maybe<T> is not. Maybe comes from some functional-programming libraries rather than TypeScript's standard library, so the compiler does not provide it out of the box.
Partial, Pick, and Readonly are built in. Maybe is not part of TypeScript's standard library (it comes from some FP libraries).
TypeScript/declarations/interface-vs-type
Which statements about interface vs type are true?
Options
- Interfaces support declaration merging; type aliases do not
typecan alias a union; an interface cannot be a union- Only
typealiases can be extended or implemented - Both can describe the shape of an object
Show answer
Three statements hold: interfaces support declaration merging while type aliases do not, type can alias a union while an interface cannot be a union, and both can describe an object's shape. The claim that only type aliases can be extended or implemented is false — interfaces extend via extends and types compose via &.
Interfaces merge across declarations and type can name unions/primitives/tuples. Both describe object shapes, and both can be extended (interfaces via extends, types via &), so (c) is false.
TypeScript/narrowing/exhaustiveness
A value of type never is assignable to every other type.
Show answer
True. never is the bottom type, so a value of type never is assignable to every other type, while nothing except never is assignable to it. This is exactly what powers the const _exhaustive: never = x pattern that enforces exhaustive switch statements.
never is the bottom type: it is assignable to everything, and nothing (except never) is assignable to it. That is what makes the const _exhaustive: never = x pattern enforce exhaustive switches.
TypeScript/generics/generic-functions
What does this log?
function first<T>(arr: T[]): T | undefined {
return arr[0];
}
console.log(first([10, 20, 30]));Show answer
10
The generic first infers T = number from the argument and returns arr[0], which is 10. Types are erased at runtime; the behaviour is just plain array indexing.
TypeScript/narrowing/typeof-instanceof
What does format(3) log?
function format(x: string | number): string {
return typeof x === 'string' ? x.toUpperCase() : x.toFixed(1);
}
console.log(format(3));Options
- 3.0
- 3
- TypeError
- NaN
Show answer
3.0
typeof 3 === 'string' is false, so TypeScript narrows x to number in the else branch and (3).toFixed(1) produces the string "3.0".
TypeScript/narrowing/type-guards
Under strict, this does not type-check. What is the problem?
function greet(name?: string) {
return 'Hello, ' + name.toUpperCase();
}Options
nameisstring | undefined, soname.toUpperCase()is unsafe — it can beundefined- You cannot concatenate strings with
+in TypeScript - The function must declare an explicit return type
- Optional parameters must appear before required ones
Show answer
name is string | undefined, so name.toUpperCase() is unsafe — it can be undefined
An optional parameter has type string | undefined. Calling .toUpperCase() without narrowing is rejected under strictNullChecks. Guard it (name?.toUpperCase() or an if (name) check) or give it a default.
TypeScript/narrowing/discriminated-unions
What is a discriminated union and why is it useful?
Show answer
A discriminated (tagged) union is a union of object types that share a common literal property — the discriminant. Switching on that property lets TypeScript narrow the value to one exact member, so you can handle each case type-safely and get exhaustiveness checking for free.
The shared literal field (e.g. type: 'circle' | 'square') is what lets the compiler narrow inside a switch. Adding a never default then enforces that every member is handled.
TypeScript/advanced-types/mapped-types
For type T = { a: 1; b: 2 }, what does keyof T produce?
Show answer
'a' | 'b' — a union of T's property keys (as string literal types).
keyof turns an object type's keys into a union of literal types. Combined with generics (<K extends keyof T>) it powers type-safe property access like Pick and get(obj, key).
TypeScript/utility-types/pick-omit
What is the difference between Pick<T, K> and Omit<T, K>?
Show answer
Pick<T, K> keeps only the keys listed in K; Omit<T, K> removes those keys and keeps the rest. They are complements.
Reach for Pick when you want a small subset and Omit when you want everything except a few keys (e.g. stripping id before a create call).
TypeScript/types-basics/arrays-tuples
What is the difference between the type [string, number] and (string | number)[]?
Options
[string, number]is a tuple: a fixed length of 2 with element 0 astringand element 1 anumber;(string | number)[]is a variable-length array of either type- They are identical; the tuple syntax is just shorthand
[string, number]is an array of any length;(string | number)[]has a fixed length- Tuples cannot mix types, so
[string, number]is invalid
Show answer
[string, number] is a tuple: a fixed length of two, with a string at position 0 and a number at position 1. (string | number)[] is a variable-length array whose elements may each independently be a string or a number. The tuple pins down both length and per-position types; the array constrains neither.
A tuple type fixes both the length and the type at each position, so [string, number] requires exactly a string then a number. (string | number)[] is an ordinary array of any length whose elements may each be a string or a number.
TypeScript/types-basics/literal-types
In let x = 'hello', what type is inferred for x?
Options
string— a mutableletbinding widens the literal to its base type'hello'— the literal type is preservedanyString(the object wrapper type)
Show answer
The inferred type is string. Because a let binding can be reassigned, TypeScript widens the string literal to its base type string rather than keeping it pinned to 'hello'. Declaring it with const (or adding as const) would instead preserve the narrow literal type 'hello'.
TypeScript widens a string literal to string for a mutable let because the binding can be reassigned. Using const x = 'hello' (or as const) would instead infer the literal type 'hello'.
TypeScript/utility-types/returntype-parameters
Given function makeUser() { return { id: 1, name: 'Ada' }; }, what is ReturnType<typeof makeUser>?
Options
{ id: number; name: string }typeof makeUser() => { id: number; name: string }{ id: 1; name: 'Ada' }
Show answer
It is { id: number; name: string }. typeof makeUser gives the function's type, and ReturnType<F> extracts whatever that function returns. The literal values 1 and 'Ada' widen to number and string because the returned object is mutable rather than declared as const.
typeof makeUser is the function type, and ReturnType<F> extracts what that function returns — here { id: number; name: string }. The literals widen because the return expression is a mutable object, not as const.
TypeScript/advanced-types/template-literal-types
What does the type type Event = `on${'Click' | 'Hover'}` resolve to?
Options
'onClick' | 'onHover'`on${string}`'on' | 'Click' | 'Hover'string
Show answer
It resolves to 'onClick' | 'onHover'. A template literal type distributes over the union sitting in its interpolation slot, producing one concatenated literal per union member. This is the mechanism behind typed helpers such as deriving event-handler key names from a set of event names.
A template literal type distributes over the union in its interpolation slot, producing one literal per member: 'onClick' | 'onHover'. This is how helpers like typed event-handler keys are derived.
Sources
The official documentation these questions are checked against:
Related interview questions
Job market
See typescript salaries and hiring demand from live job postings.
Practice this for real
CodePrep turns your target job description into an adaptive quiz from a bank of tagged questions, scores your answers, and resurfaces the topics you miss.