TypeScript Interview Mock sample questions with answers
10 questions from the TypeScript Interview Mock practice bank, spread across its domains. Pick your answer, then open the explanation to see why each option is right or wrong.
- Question 1Generics and Type-Level Programming
This type resolves to
0 | 1, becausebooleanis the uniontrue | falseand the conditional distributes over it.type A = boolean extends true ? 1 : 0;- A
True
- B
False
Show the answer and explanation
Answer: B
Distribution happens only when the checked type is a generic type parameter that is later instantiated with a union. Here
booleanappears literally, so the check istrue | falseextendstrue, which fails: the result is0. Withtype IsTrue<T> = T extends true ? 1 : 0,IsTrue<boolean>would be0 | 1.Why the other options are wrong
A. It is false: distribution needs a naked type parameter, and here
booleanis written directly.
- A
- Question 2Type System Foundations
Given
interface Cfg { port: number }, which three lines report an excess property error forhost? (Choose three.)function make(): Cfg { return { port: 1, host: 'x' }; } // 1 const viaFn: () => Cfg = () => ({ port: 1, host: 'x' }); // 2 const list: Cfg[] = [{ port: 1, host: 'x' }]; // 3 const nested: { cfg: Cfg } = { cfg: { port: 1, host: 'x' } }; // 4 const extra = { host: 'x' }; const spread: Cfg = { port: 1, ...extra }; // 5Choose 3.
- A
Line 1
- B
Line 2
- C
Line 3
- D
Line 4
- E
Line 5
Show the answer and explanation
Answer: A and C and D
Freshness follows the literal wherever it is directly checked against a declared type: return statements of annotated functions, array elements and nested properties. Two common gaps: an arrow function assigned to a function type infers its own return type first, so line 2 compiles (annotate
(): Cfg =>to get the check), and spread properties are never treated as excess.Why the other options are wrong
B. The arrow's return type is inferred from the literal, then the function types are compared, so no excess check runs.
E. Properties that arrive through a spread are not checked for excess.
- A
- Question 3Narrowing, Functions and Classes
Shapehas three members (circle, square, triangle). What does the compiler report?function area(s: Shape): number { switch (s.kind) { case "circle": return s.r; case "square": return s.s; default: s satisfies never; throw new Error("unreachable"); } }- A
Nothing, because
satisfiesonly checks object literals - B
An error saying that the function lacks an ending return statement
- C
TS1360: type
{ kind: "triangle"; b: number; }does not satisfy the expected typenever - D
A warning that
sis unused in the default branch, whichnoUnusedLocalsreports
Show the answer and explanation
Answer: C
expr satisfies never(TypeScript 4.9+) is a compact exhaustiveness check that needs no helper variable. When every case is handled it compiles; when one is missing, TypeScript names the leftover type. Keep thethrowso the function still has a defined result at runtime.Why the other options are wrong
A.
satisfiesworks on any expression, including identifiers.B. The
throwends that path, so every path returns or throws.D. This is a type error, not an unused-variable report.
- A
- Question 4Compiler, Declarations and Modules
This global declaration file worked for months. After someone added the first line,
window.appVersionnow fails with TS2339 everywhere. Why, and what is the fix?// globals.d.ts import type { Foo } from "./foo"; interface Window { appVersion: string; foo: Foo; }- A
Type-only imports are not allowed in declaration files; move the
Fooimport into each file that uses it - B
The interface needs
exportnow, so change it toexport interface Windowso that the merge happens - C
The import made the file a module, so
Windowis now module-local; wrap it indeclare global { … } - D
The DOM lib is no longer loaded once any declaration file imports a module, so add "dom" to
libagain
Show the answer and explanation
Answer: C
Any top-level import or export turns a file into a module, and declarations in a module are scoped to it. The
interface Windowabove therefore declares a new, unrelated local type instead of merging with the globalWindow. The fix keeps the import and moves the augmentation intodeclare global { interface Window { … } }, which is only legal inside a module.Why the other options are wrong
A. Imports are allowed in .d.ts files. The problem is what the import does to the file's scope.
B. Exporting it creates a module-local interface named Window; it still would not merge with the global one.
D. The DOM lib is still loaded; TS2339 says Window exists but lacks the property.
- A
- Question 5Applied TypeScript
Which statements about
satisfiesare true? (Choose two.)Choose 2.
- A
It reports an error if the expression doesn't conform to the type, such as a misspelled key
- B
The variable keeps the expression's own inferred type rather than the checked type
- C
Like
as, it lets you claim a type the value doesn't actually have - D
It adds a runtime validation step that throws if the shape is wrong
- E
It always keeps string literals, even where the target type is plain
string
Show the answer and explanation
Answer: A and B
expr satisfies TchecksexpragainstT(with excess-property checks) but leaves the variable typed asexpr's own inferred type. It doesn't make a value conform the wayaspretends to, and it doesn't freeze literals by itself. Combine it withas const(as const satisfies T) when you need exact literal values.Why the other options are wrong
C.
satisfiesis a check, not an assertion. A non-conforming value is an error.D. Like every type operator, it is erased during compilation.
E. Values contextually typed by
stringstill widen tostring; addas constto keep literals.
- A
- Question 6Generics and Type-Level Programming
How many members does the union
Combohave?type Combo = `${'a' | 'b'}-${'x' | 'y' | 'z'}`;- A
5, one per union member across both placeholders
- B
6, the cross product of 2 × 3 combinations
- C
1, because it becomes the single literal
'a|b-x|y|z' - D
2, one for each member of the first placeholder only
Show the answer and explanation
Answer: B
Placeholders in a template literal type each distribute, so the result is the cross product: 2 × 3 = 6 literals (
'a-x' | 'a-y' | 'a-z' | 'b-x' | 'b-y' | 'b-z'). With large unions this grows fast, and TypeScript errors once a union passes 100,000 members.Why the other options are wrong
A. Members are not just listed; every combination of the two placeholders is produced.
C. Unions are expanded into separate literals, not joined into one string.
D. Each placeholder distributes, so both contribute to the count.
- A
- Question 7Type System Foundations
With
noUncheckedIndexedAccess: true, what are the types offirst,val,sandt0?declare const arr: string[]; declare const dict: Record<string, number>; declare const tup: [string, number]; const first = arr[0]; const val = dict['k']; for (const s of arr) { /* ... */ } const t0 = tup[0];- A
string | undefined,number | undefined,string | undefined,string | undefined - B
string | undefined,number | undefined,string,string - C
string,number | undefined,string,string - D
string | undefined,number,string,string
Show the answer and explanation
Answer: B
noUncheckedIndexedAccessadds| undefinedto reads through index signatures, including array element access, because the key might not exist. Values produced by iteration cannot be missing, sosstaysstring, and a tuple's declared positiontup[0]is known to exist, so it staysstring. The flag is not part ofstrict; you enable it separately.Why the other options are wrong
A. Iteration and known tuple positions are not affected by the flag.
C. Array element reads are index reads too, so
arr[0]also gets| undefined.D.
Record<string, number>has a string index signature, so it is affected too.
- A
- Question 8Narrowing, Functions and Classes
Given
class P1 { f(x: string) { return x; } }, which three subclasses compile understrict? (Choose three.)Choose 3.
- A
class P3 extends P1 { f(x: "a") { return x; } } - B
class P4 extends P1 { f(x: string | number) { return String(x); } } - C
class P5 extends P1 { f() { return "none"; } } - D
class P6 extends P1 { f(x: string, y: string) { return x + y; } } - E
class P7 extends P1 { f(x: string) { return 1; } }
Show the answer and explanation
Answer: A and B and C
An override must be assignable to the base member. Returning a different type and requiring more parameters both fail with TS2416. Taking fewer or wider parameters is safe. A narrower parameter (
"a") is unsound but still accepted, because methods are compared bivariantly even understrictFunctionTypes. Only function-typed properties get the strict check.Why the other options are wrong
D. A second required parameter would break callers that pass one argument (TS2416).
E. The return type
numberis not assignable tostring(TS2416).
- A
- Question 9Compiler, Declarations and Modules
This file is in a project with
"allowJs": true, "checkJs": true. Which two statements are true? (Choose two.)// math.js /** @param {number} a @param {number} b */ export function add(a, b) { return a + b; } add(1, "2"); /** @type {string} */ export let label = 5;Choose 2.
- A
add(1, "2")is reported, because the JSDoc@paramtypes are enforced - B
let label = 5is reported, because@type {string}declares the variable as a string - C
Nothing is reported, because type errors are never shown for
.jsfiles - D
The file must be renamed to
.tsbefore JSDoc types are read - E
// @ts-ignoreand// @ts-expect-errordon't work in.jsfiles
Show the answer and explanation
Answer: A and B
allowJslets.jsfiles join the program, andcheckJstype-checks them using inference plus JSDoc (@param,@type,@typedef,@template). This is a common first step in migration: you get errors in existing JavaScript before renaming a single file. A// @ts-checkcomment enables checking for one file at a time.Why the other options are wrong
C. That is true with
allowJsalone;checkJsturns checking on.D. JSDoc types are read in
.jsfiles; that is the point of checkJs.E. Both directives work in checked JavaScript files.
- A
- Question 10Applied TypeScript
An API client is typed from a route map:
type Routes = { "/users": { res: User[] }; "/users/:id": { res: User }; }; declare function get<P extends keyof Routes>(path: P): Promise<Routes[P]["res"]>;What type does
get("/users")have, and what happens withget("/posts")?- A
Promise<User | User[]>, andget("/posts")returnsPromise<never> - B
Promise<User[]>, andget("/posts")is a compile error - C
Promise<User[]>, andget("/posts")compiles withPromise<unknown> - D
Promise<Routes["/users"]>, andget("/posts")is a compile error
Show the answer and explanation
Answer: B
A route map turns path strings into a typed contract: the inferred literal
Pselects the right response type, and unknown paths fail to compile. Generating such maps from an OpenAPI spec or sharing them between client and server is how tools like tRPC and typed fetch wrappers work.Why the other options are wrong
A. P is inferred as the literal "/users", so indexing picks exactly that route's response.
C. An invalid key isn't widened to unknown; the
extends keyof Routesconstraint rejects it.D. The return type indexes one level deeper, into
["res"], givingUser[].
- A
Practise all 479 TS questions
Start with the free 15-question diagnostic. It shows where to focus, and your results carry over if you sign up.