All 75 TypeScript quiz questions below come with a short explanation, visible right on the page — no sign-in needed. They're grouped by beginner and intermediate levels and 35 subtopics, so you can revise one part at a time. Choose Try TypeScript quiz above to take a scored run and review the questions you got wrong.
Which statement correctly describes the difference between interface and type alias in TypeScript?
A.interface is checked at runtime while type is only checked at compile time
B.type is only for primitives and interface only for objects
C.type cannot take part in extends, so inheritance requires interface
D.interface supports declaration merging (same-named declarations are combined); a type alias does not
Answer: D
interface supports declaration merging and only describes object shapes; type alias is more flexible (union, intersection, tuple, primitive, conditional type) but doesn't merge. Common rule: interface for extensible public APIs, type for unions and advanced types.
What is the difference between any, unknown, and never in TypeScript?
A.any disables checking; unknown must be narrowed; never has no values at all
B.never is an alias for null | undefined
C.unknown and any are identical apart from the name
D.any only works on parameters while unknown only works on variables
Answer: A
any disables type checking entirely, losing type safety. unknown accepts any value but forces you to narrow (typeof, instanceof, type guard) before using it — the safe alternative to any. never is a type with no values: a function that always throws, or a branch fully eliminated in an exhaustive check.
What does the Partial<T> utility type do, and what is its typical use case?
A.It removes properties whose value is undefined from the object at runtime
B.It makes every property optional at every level of nesting (deep)
C.It picks a subset of T's properties from a list of keys
D.It makes every property of T optional — typically for an update (PATCH) payload
Answer: D
Partial<T> creates a new type with all of T's properties optional (shallow). Typical use: an update function taking Partial<User> so the client only sends changed fields in a PATCH request. The opposite is Required<T>, which makes every optional property required.
In an interface, how does nickname?: string differ from bio: string | undefined?
A.nickname? means the property is read-only and cannot be reassigned
B.The two forms are entirely equivalent, differing only in syntax
C.The question-mark form allows the key to be absent; the other requires the key to be present
D.bio: string | undefined automatically defaults to an empty string
Answer: C
prop?: T lets you omit the key entirely when creating the object (type when reading is T | undefined). prop: T | undefined still requires the key to be present — only the value may be undefined. Also, readonly prop blocks reassignment after initialization, but only at compile time.
What is TypeScript and what is its main benefit over plain JavaScript?
A.A superset of JavaScript with static typing that compiles to JS — catching errors at compile time with better IDE support
B.An entirely new language replacing JavaScript, running directly in the browser with no compilation
C.A version of JavaScript that runs faster because engines optimise using the type declarations
D.A runtime library that checks data types while the application runs to prevent errors
Answer: A
TypeScript is a superset of JavaScript that adds static typing and compiles to JS. Main benefits: catches errors at compile time instead of runtime, better IDE support (autocomplete, safe refactoring), self-documenting code. Most useful on large projects, team work, and long-lived codebases.
What happens at the line count = "ten" in the following code?
ts
let count = 0
count = 'ten'
A.A compile error — the variable's number type was inferred from its initial value
B.Valid — with no type annotation, count defaults to any
C.Valid at compile time but an error when it runs
D.A compile error because let does not allow reassignment
Answer: A
Compile error. Type inference infers count: number from the initial value 0 — no annotation needed. From then on every assignment must be a number; assigning "ten" errors at compile time. Thanks to inference, annotations are usually only needed for function parameters, return types, and variables declared without a value.
Why does the following code fail to compile, and what is the correct fix?
ts
functionprintId(id: string | number) {
console.log(id.toUpperCase())
// Error: Property 'toUpperCase' does not exist on type 'string | number'
}
A.Union types cannot be used for parameters — split it into separate functions for string and number
B.The error is the missing return type annotation — adding : void fixes it
C.Fixing it with (id as string).toUpperCase() is the recommended approach
D.On a union type you may only call members common to every member, and number has no toUpperCase
Answer: D
The union string | number means the value can be either — so TypeScript only allows calling members that exist on BOTH types. toUpperCase only exists on string, hence the error. Fix: narrow with if (typeof id === "string") — inside that branch id is narrowed to string and the method call is safe.
A.A tuple fixes the count and the type at each position; an array does not
B.A tuple requires every element to share one type, and only an array allows mixing
C.The two are equivalent — a tuple is just shorthand for an array of a union
D.A tuple is its own runtime data structure, not a JavaScript array
Answer: A
Tuple [string, number] has a fixed length of 2 and a type per position: index 0 is string, index 1 is number — wrong order or extra elements both fail to compile. Array (string | number)[] accepts any length and each element is one of the two types. Tuples are good for structured value pairs: coordinates, key-value pairs, useState returns.
Given type Status = 'loading' | 'success' | 'error', what values does a variable const s: Status accept?
A.Those three strings plus undefined, since the variable may not be assigned
B.An invalid declaration — restricting a value set requires an enum
C.Any string at all — a literal union is only a hint for IDE autocomplete
D.Exactly the three strings 'loading', 'success', 'error'
Answer: D
Exactly 3 values 'loading', 'success', 'error' — a literal type is a type equal to exactly one specific value, and a union of them forms a closed set. This is how you make enum-like types with no runtime overhead, very common for API state. Pitfall: let s = 'loading' infers string (widening), so you need const or as const to keep the literal.
In const canvas = document.getElementById('canvas') as HTMLCanvasElement, what does the as keyword do?
A.Asserts a type for the compiler, with effect only at compile time
B.It creates a copy of the value with the new type, leaving the original intact
C.It converts the value to the new type at runtime, like a cast in Java/C#
D.It checks the type at runtime and throws if the element is not an HTMLCanvasElement
Answer: A
The type assertion value as Type overrides the compiler's inferred type and exists only at compile time — no checking, no conversion at runtime. Use it when you know the type more precisely than the compiler (DOM queries, JSON.parse). Overuse loses type safety; as unknown as Type (double assertion) is a sign of a problematic type design.
const el = document.querySelector('.btn')!
el.addEventListener('click', handleClick)
A.It replaces a null value with a default element automatically so the code cannot fail
B.A runtime null check that throws a clear error if the element does not exist
C.The boolean negation operator — turning the query result into true/false
D.A non-null assertion — telling the compiler the value is definitely not null or undefined
Answer: D
That's the non-null assertion: telling the compiler the preceding value is definitely not null/undefined, removing them from the type at compile time. There is no runtime check — if the element doesn't exist, the code still crashes. Only use it when you're sure the value exists; optional chaining (?.) or an explicit if check is safer.
A.Declaring : void is mandatory for a function with no return, and omitting it is a compile error
B.Returns no value; return with a value in : void is a compile error
C.void and never are the same — both mean the function returns nothing
D.void means the function may not contain a return statement in any form
Answer: B
void represents the return type of a function that doesn't return a meaningful value — the function is called for its side effect. In a function declared : void, returning a value is a compile error, but return; for early exit is still valid. Different from never: a void function finishes normally, a never function never finishes normally (always throws).
A.It forces every variable to have an explicit type annotation
B.It switches on a group of strict-checking flags at once
C.It turns every compiler warning into a compile error
D.It checks types at runtime rather than only at compile time
Answer: B
It turns on a group of strict checks at once: banning implicit any, null and undefined checking, class property initialization checking, implicit this checking, and strict function type checking. This is the recommended setting for every new project.
What types are inferred for const x = "hello" and let y = "hello"?
A.x is string and y is a literal type, because let holds its value more tightly
B.x has the literal type "hello" and y is string
C.Both are literal types, since the value is known at compile time
D.Both are string, since the initial values are the same
Answer: B
x has the literal type "hello" because a const can't be reassigned. y is widened to string because it could later hold a different string. This is called literal widening and directly affects assignment to a union of literals.
When does the private keyword on a class property take effect?
A.Only when the class is declared in its own module
B.Only at runtime, while every access is valid at compile time
C.Both at compile time and at runtime, because the compiler emits protective code
D.Only at compile time; at runtime the property is still reachable
Answer: D
Only at compile time. It is erased along with all other type information, so the emitted JavaScript still reads and writes that property normally. For real runtime privacy you need a JavaScript field with a # prefix.
A.When a function does not declare an explicit return type
B.When importing a module with no accompanying type declaration file
C.When any variable is declared with an explicit any type
D.When the compiler cannot infer a type and would default to any
Answer: D
When the compiler cannot infer a type and would have to default to any — typically a function parameter with no annotation. It only blocks implicitlyany; writing it explicitly is still accepted because that is a deliberate choice.
Why prefer unknown over any when the type is not yet known?
A.Because unknown forces narrowing before use
B.Because unknown can be assigned safely to any other type
C.Because unknown uses less memory when the program runs
D.Because any has been deprecated in newer versions
Answer: A
Because unknown forces you to narrow the type before doing anything with the value, while any disables checking entirely and it spreads to every expression downstream. A wrong assertion with any won't be caught anywhere until the error occurs at runtime.
How do you type a function taking two numbers and returning a number?
A.Declare an interface and assign the function to a variable of that type
B.No declaration is needed because the type is inferred from the call sites
C.Annotate each parameter and the return type after a colon
D.Use a special comment above the function declaration
Answer: C
Annotate each parameter and the return type after the colon. The return type is usually optional since it's inferred automatically, but parameter types are required — omitting them errors under strict mode.
A.One is for primitives and the other for object types
B.They are entirely equivalent, differing only in spelling
C.One checks types at runtime and the other only at compile time
D.One creates a fixed-length array and the other a mutable one
Answer: B
Completely equivalent, only written differently. Which one to pick is a team convention, typically enforced by a lint rule to keep the whole project consistent.
What is the meaning difference between null and undefined in TypeScript?
A.One is for objects and the other for primitives
B.They are entirely equivalent in every context
C.One exists only at compile time and the other at runtime
D.One is deliberately empty, the other has not been assigned
Answer: D
By convention: one value means intentionally empty, the other means not yet assigned. With strict null checks enabled they're two distinct types, so assigning the wrong one errors.
The following code fails to compile. What is the idiomatic fix?
ts
function getLength<T>(arg: T): number {
return arg.length// Error: Property 'length' does not exist on type 'T'
}
A.A generic cannot access a property — a separate overload is required per type
B.Assert inside the function: return (arg as string).length
C.Change the parameter type to any: function getLength(arg: any)
D.Add a generic constraint: function getLength<T extends { length: number }>(arg: T)
Answer: D
Without a constraint, T could be any type, so the compiler won't allow accessing .length. The idiomatic fix is to add the constraint T extends { length: number } — every argument must have a length of type number, and the function stays generic and type-safe with string, array, or any object that has length.
What is the resulting type of type X = string & number, and why?
A.never — no value can be both a string and a number
B.any — the compiler cannot handle it so it skips checking
C.string | number — & and | are equivalent for primitives
D.string — the first type listed takes precedence
Answer: A
The result is never. An intersection A & B requires a value to belong to both A and B; no value is both a string and a number, so the intersection set is empty. For objects, & merges the properties of both — that's the main use case: type AdminUser = User & { adminRole: string }.
At the line return val.toFixed(2), what type does TypeScript infer for val?
ts
functionformat(val: string | number | Date) {
if (typeof val === 'string') {
return val.toUpperCase()
}
if (val instanceofDate) {
return val.toISOString()
}
return val.toFixed(2)
}
A.string | number | Date — the declared type is unchanged inside the function body
B.number | Date — instanceof is not a valid type guard
C.number — after typeof and instanceof return, the union is just number
D.unknown — the compiler cannot determine it so it falls back to the safest type
Answer: C
The type is number. TypeScript uses control flow analysis: the guard typeof val === "string" eliminates string, the guard val instanceof Date eliminates Date — both branches return, so below the union only number remains, allowing a safe call to .toFixed().
What is the inferred type of dirs in the following code?
ts
const dirs = ['left', 'right'] asconst
A.['left', 'right'] — a tuple, but still mutable through push/pop
B.string[] — an array of strings, as it would be without as const
C.('left' | 'right')[] — an array of any length holding those two values
D.readonly ['left', 'right'] — a readonly tuple of exactly two literal types in order
Answer: D
The type is readonly ['left', 'right'] — a readonly tuple where each element is a literal type. Without as const, TypeScript widens it to string[]. A const assertion keeps the narrowest type: useful for creating strongly-typed constants and deriving a union from them via typeof dirs[number].
Select ALL correct statements when comparing enum with a union of string literals in TypeScript.
A.A union of string literals can be iterated at runtime to list its values
B.A string enum auto-assigns increasing values 0, 1, 2 like a numeric enum
C.A numeric enum has reverse lookup: Direction[0] returns the member name "Up"
D.The const obj = {...} as const + typeof obj[keyof typeof obj] pattern is the community's recommended enum replacement
E.An enum generates JavaScript at runtime, while a union of literals is erased entirely at compile time
Answer: C, D, E
An enum generates a real JavaScript object at runtime (a numeric enum also has reverse lookup), whereas a union of literals is fully erased at compile time — lighter but not iterable. The current trend: use a const object + as const to get both a union type and runtime values, with better tree-shaking than an enum.
const config = { host: 'localhost', port: 3000 }
type K = keyof typeof config
A.string — an object's keys are always strings
B.A compile error — keyof cannot be applied to a variable, only to a type
C.'localhost' | 3000 — the union of the object's values
D.'host' | 'port' — keyof typeof gives the union of the keys
Answer: D
K is 'host' | 'port'. typeof config (a type query) gets the type of the value: { host: string; port: number }; keyof applied to that type yields a union of the literal keys. The keyof typeof combination is the standard idiom for deriving a type from an existing object.
B is { id: number; name: string }. ReturnType<typeof fetchUser> gets the function's return type — for an async function that's Promise<{...}>. Awaited<T> unwraps the Promise (recursively for nested Promises). The Awaited<ReturnType<typeof fn>> combo is the standard way to get the data type from a fetch function without duplicating the declaration.
How does enabling strictNullChecks in tsconfig change type checking behavior?
A.Every variable becomes non-null automatically, so null checks are no longer needed
B.It only affects variables declared as any
C.null and undefined can no longer be assigned to other types
D.The compiler inserts null checks into the generated JavaScript
Answer: C
When strictNullChecks is enabled, null and undefined become their own types and can't be assigned to other types. To allow a nullable value you must declare a union (string | null) and narrow before use — the compiler errors right where a null is possible instead of letting a "cannot read property of undefined" error happen at runtime.
A.satisfies works exactly like as Record<string, Color> — both coerce an object literal
B.satisfies inserts a runtime type check, making it safer than an annotation
C.satisfies checks the value against the type while preserving the inferred type
D.Because Record<string, Color> cannot be used as an annotation for an object literal, only after satisfies
Answer: C
satisfies (TS 4.9) checks that a value matches a type without widening the inferred type: palette.green stays string, so calling toUpperCase() is valid. The : Record<string, Color> annotation overrides instead — every property takes the union type Color, so you must narrow before using a specific method. You get both directions: wrong values still error, correct values keep the narrowest type.
C.A two-member union: 'top-x' | 'bottom-y' — paired by matching position
D.A compile error — a union may not sit inside a template literal type's placeholder
Answer: B
Cell is a 4-literal union: 'top-x' | 'top-y' | 'bottom-x' | 'bottom-y'. Template literal types expand the cross product of every combination of the unions in the placeholders — 2 × 2 = 4. This is a tool for generating type-safe CSS properties, event names, route paths instead of listing them by hand.
What is the type Draft<Cfg> in the following code?
typescript
interfaceCfg {
readonlyhost?: stringreadonlyport?: number
}
typeDraft<T> = { -readonly [K in keyof T]-?: T[K] }
typeResult = Draft<Cfg>
A.A compile error — -readonly and -? may not appear in the same mapped type
B.{ host?: string; port?: number } — only readonly can be removed; ? cannot be removed by a mapped type
C.{ host: string; port: number } — the - removes modifiers: -readonly allows reassignment and -? makes properties required, also dropping undefined from the type
D.{ host: string | undefined; port: number | undefined } — the properties become required but undefined stays in the value type
Answer: C
The result is { host: string; port: number }. In a mapped type, the - prefix strips a modifier: -readonly allows reassignment, -? makes the property required and also removes undefined from its value type. This is exactly how Required<T> works; the opposite direction (readonly, ?, or +readonly, +?) is how Readonly<T> and Partial<T> are implemented.
Question 12·Declaration Merging· select all that apply
Select ALL correct statements about declaration merging in TypeScript.
A.Same-named type aliases merge just like interfaces, only the syntax differs
B.Two same-named class declarations also merge their members like interfaces
C.Module augmentation relies on this very mechanism
D.Two same-named interfaces in the same scope are merged
E.A same-named property with a different type is a compile error
Answer: C, D, E
Declaration merging: interface (and namespace) declarations with the same name in the same scope are merged into one by the compiler. Properties with the same name must have the same type — a different type is a compile error. type aliases and class do not merge — a name collision is a Duplicate identifier error. Module augmentation is an application of merging to extend third-party library types.
A.{ passwordHash: string } — Omit keeps exactly the keys passed in
B.The original object has its passwordHash field deleted at runtime when accessed through this type
C.{ id: number; name: string } — Omit<T, K> builds a new type with every property of T except the keys in K
D.{ id: number; name: string; passwordHash?: string } — Omit only makes the key optional rather than removing it
Answer: C
PublicUser is { id: number; name: string }. Omit<T, K> creates a type with all of T's properties except the keys in K — here dropping passwordHash. The complementary pair is Pick<T, K>, which keeps exactly the listed keys. Both are type-level only, no runtime data change; to actually drop a field when returning from an API you must write destructuring code.
A.A compile error — Exclude requires the second argument to be a valid subset of T
B.'admin' | 'editor' — Exclude<T, U> removes from the union T the members assignable to U
C.'admin' | 'editor' | 'viewer' — Exclude does not change a literal union and only works on objects
D.'viewer' — Exclude keeps exactly the member passed as the second argument
Answer: B
Privileged is 'admin' | 'editor'. Exclude<T, U> removes from union T every member assignable to U. The complement is Extract<T, U>, which keeps exactly the members matching U (e.g. Extract<string | number, string> = string). Both are built on distributive conditional types with a false branch returning never to filter members.
A.Dict accepts any number of string keys; dict["anything"] = 5 is valid because the key set is open
B.With Dict, accessing dict.missing is a compile error because the key was never declared
C.Record<'host' | 'port', string> creates a closed object with exactly two required keys — omitting port is a compile error
D.Record<string, number> and { [key: string]: number } are near-equivalent for an open key set
E.An index signature only allows string keys, while Record does not accept a string key
Answer: A, C, D
An index signature { [key: string]: T } describes an open key set — any string key is valid and accessing any key yields type T. Record<K, V> with K as a literal union creates a closed object with exactly those keys. When K is string, Record<string, V> and an index signature are equivalent. Both accept string/number/symbol keys.
Without passing a type argument, what is the type of the data property in ApiResponse?
typescript
interfaceApiResponse<T = unknown> {
data: T
status: number
}
type R = ApiResponsetype D = R['data']
A.unknown — the generic default T = unknown applies
B.never — an unassigned type parameter is the empty type
C.A compile error — every generic requires a type argument
D.any — a generic with no type argument falls back to any
Answer: A
The type is unknown. The generic default T = unknown makes the type argument optional — writing ApiResponse without braces means T takes the default. Defaults must come after required type parameters and must satisfy any constraint (T extends X = Y). Passing it explicitly (ApiResponse<User>) overrides the default.
How do the target and lib options in tsconfig differ?
A.target is for browsers and lib for the server
B.target is mandatory while lib is inferred automatically and can be omitted
C.target applies to your source while lib applies to your dependencies
D.target decides the output syntax, lib decides which APIs are available for checking
Answer: D
target determines the syntax version of the emitted code — newer syntax is compiled down to an older form. lib declares the APIs available in the runtime environment so the compiler can type-check them. Setting the wrong lib makes code compile but fail at runtime because the function doesn't exist.
How does import type { User } from "./types" differ from import { User }?
A.It can only import types, not interfaces or classes
B.It is erased entirely on compilation and creates no runtime import
C.It allows importing from a file not yet compiled to JavaScript
D.It checks types more strictly than an ordinary import
Answer: B
It tells the compiler that only a type is being imported, so the statement is erased entirely from the emitted code. That keeps the module out of the download bundle and avoids circular dependencies that exist only at the type level.
B.Configuration describing how the compiler should handle a directory
C.TypeScript source already compiled down to JavaScript
D.Shared types for the whole project
Answer: A
It contains only type declarations — function signatures, interface shapes, variable types — with no implementation. The purpose is to describe the shape of already-compiled JavaScript so the compiler can type-check the places that use it.
Why does assigning an object literal with an extra property error, while assigning through an intermediate variable does not?
A.Because an object literal is treated as read-only and so checked more strictly
B.Because the intermediate variable loses the original object's type information
C.Because the compiler only checks the type on the first assignment
D.Because excess property checking applies only to object literals
Answer: D
Because excess property checking is a separate rule that only applies to object literals assigned directly. Normal structural typing allows an object to have more properties than required, so assigning through an intermediate variable is valid.
What does a function declared as function isCat(a: Animal): a is Cat do?
A.It coerces the argument to the target type before returning
B.It narrows the argument's type in the true branch of a conditional
C.It checks the type at runtime and throws if it does not match
D.It registers this type in a system for reuse elsewhere
Answer: B
It's a type predicate: the compiler trusts the declaration and narrows the argument's type in the true branch. Inside the if (isCat(animal)) block, the variable is treated as the narrower type, so its specific properties become accessible.
A.It only works when the union members share a common discriminant field
B.It walks every property of the object and matches the shape against each member
C.It compares the property's value against a literal type
D.It keeps the members that declare the property being checked
Answer: D
It keeps the union members that declare the checked property and removes those that don't. This is useful when members have no common discriminant field but differ in their set of properties.
What does the constraint <K extends keyof T> do in a property-getter function?
A.It guarantees the property exists at runtime, not only at compile time
B.It coerces the return type to any for more flexibility in use
C.It only allows real property names to be passed and infers the exact return type
D.It lets the function take several property names in one call
Answer: C
It restricts the parameter to only accept property names that actually exist on the type, and more importantly it lets the return type be inferred precisely. The compiler knows the specific key passed, so it returns the type of that exact property rather than a union of all types.
A.The compiler infers a string type when there is not enough information
B.The type argument must be a string or a subtype of it
C.Using Box without a type argument makes T a string
D.The value inside the box is initialised to an empty string
Answer: C
If you use Box without specifying a type argument, T defaults to string. This lets you omit the type argument in the most common case while still allowing a different type to be specified when needed.
A.Waiting for the compiler to resolve nested conditional types
B.Getting the type a Promise resolves to
C.Turning a synchronous function into an asynchronous one at the type level
D.Marking a type as something that must be awaited before use
Answer: B
It extracts the type of the value a Promise resolves to. It unwraps multiple layers, so a Promise nested inside a Promise still yields the final type — exactly matching how await behaves in real code.
Filtering with arr.filter(x => x !== null) still yields a type including null. What is the correct fix?
A.Assert the type of the filter's result
B.Use a callback with a type predicate so the filter narrows the type
C.Switch to mapping and then removing the nullish values afterwards
D.Enable another compiler flag so it narrows automatically
Answer: B
In TypeScript <= 5.4, write the callback as a type predicate: arr.filter((x): x is NonNullable<typeof x> => x !== null). A callback returning boolean carries no narrowing information; the predicate tells the compiler the result already excludes null.
What type does JSON.parse(text) return, and how should it be handled?
A.A type inferred at compile time from the contents of the string
B.object — a non-null check is enough to use it
C.unknown — the compiler already forces narrowing before use
D.any — assign it to unknown and validate before use
Answer: D
It returns any, which completely disables type checking for everything downstream. The safe approach is to assign it immediately to an unknown variable and then validate the shape before use — either with a hand-written type predicate or a runtime validation library.
When should you choose Record<string, User> over Map<string, User>?
A.Choose an object when there are very many keys, because it is faster
B.Choose an object when insertion order must be preserved
C.Choose an object when the keys are a fixed set and it must serialise to JSON
D.Choose an object when the keys may be numbers or objects rather than strings
Answer: C
Choose an object when the key set is fixed and known, and when you need to serialize to JSON — since Map structures don't serialize directly. Choose a Map when keys are dynamic, when you add and delete frequently, or when keys aren't strings.
Why do many teams avoid enum in favour of a union of string literals?
A.Because an enum cannot be used in branching statements
B.Because an enum does not allow string values for its members
C.Because an enum generates runtime code while a union is erased entirely
D.Because a union type-checks more strictly than an enum in every case
Answer: C
Because an enum generates real JavaScript code at runtime, while a union of string literals is completely erased at compile time. A union adds no bytes to the bundle, uses the string values directly, and avoids the surprising behaviors of numeric enums.
A.When working with API data, because its shape is unknown in advance
B.When the compiler complains and the code needs to run quickly
C.When a value must be converted from one type to another
D.When you know something the compiler cannot infer
Answer: D
When you have information the compiler cannot infer — for example knowing for sure that a DOM element exists and what type it is. It's an assertion, not a check, so a wrong assertion becomes a runtime error with no prior warning.
What does declaring a parameter as readonly string[] instead of string[] provide?
A.The array is frozen so it cannot be modified from outside either
B.The array is copied before being passed into the function
C.The function runs faster because the compiler can optimise the access
D.The compiler stops the function mutating the caller's array
Answer: D
The compiler blocks every mutation of the array inside the function, so the signature becomes a verifiable promise that the function only reads. It also allows passing in readonly-marked arrays, which a normal array parameter rejects.
How does class A implements B differ from class A extends B?
A.One is checked at runtime and the other only at compile time
B.One checks the shape only, the other inherits the implementation as well
C.One is for interfaces and the other for type aliases
D.One allows several parent types while the other allows only one interface
Answer: B
implements only asserts that a class satisfies a shape — the compiler checks it then erases the keyword, no code is inherited. extends creates a real inheritance relationship at runtime: the subclass receives the parent's implementation.
What does writing constructor(private name: string) do?
A.It prevents the parameter being modified inside the constructor
B.It creates a copy of the passed value to avoid a shared reference
C.It declares a property and assigns its value automatically
D.It marks the parameter as required when constructing the object
Answer: C
This is a parameter property: the compiler generates the field declaration and the assignment statement in the constructor itself. It replaces writing both the declaration line and the assignment line by hand, and works with any access level plus the readonly keyword.
How do the void and undefined return types differ in TypeScript?
A.The void type requires the function to have a bare return statement
B.The void type can only be used for class methods
C.The two types are entirely equivalent, differing only in spelling
D.A function returning a value is still assignable where a void-returning function is expected
Answer: D
A function that returns a value can still be assigned to a void return type declaration — a special rule allows passing a function with a value where that value is ignored. The undefined type, however, only accepts a function whose result is undefined, e.g. no return or return undefined.
With exactOptionalPropertyTypes on, how does { name?: string } differ from { name: string | undefined }?
A.The optional form requires an accompanying default value
B.The second form allows the key to be absent while the first requires it
C.The two forms are equivalent, differing only in declaration syntax
D.The optional form allows the key to be absent but not to be assigned undefined
Answer: D
With exactOptionalPropertyTypes on, the optional form allows the key to be absent entirely but does not allow explicitly assigning undefined. The second form requires the key to be present but allows the value to be undefined. This lets you distinguish "not there" from "there but empty".
What is declare module "*.svg" in a .d.ts file for?
A.Specifying how the bundler should handle files with that extension
B.Allowing non-JavaScript files to be imported without an error
C.Converting that file into a JavaScript module at compile time
D.Registering a new file type with the runtime's module system
Answer: B
It tells the compiler the type of the value when importing a file that is not JavaScript. The bundler turns an image file into a path or a component, but the compiler doesn't know that and reports a missing module until this declaration exists.
What does the Result pattern ({ ok: true; data: T } | { ok: false; error: E }) provide?
A.It forces the caller to handle both the success and failure branches
B.It prevents the function throwing an exception in any circumstance
C.It logs every error occurring inside the function automatically
D.It lets the compiler check which exception types a function throws
Answer: A
It puts the possibility of failure into the return type itself, so the compiler forces the caller to check the branch before accessing the data. Unlike an exception, which doesn't appear in the signature, so the caller has no way to know the function can fail.
What does adding as const to a configuration object do?
A.The compiler optimises by inlining the values at their use sites
B.The object is frozen at runtime and can no longer be modified
C.The object is marked as a shared global constant
D.Every property becomes a literal type and the whole object becomes read-only
Answer: D
Every property is inferred as a literal type instead of a widened type, and the whole object plus any nested arrays become readonly at the type level. That lets you extract a union of the values from the object itself instead of redeclaring the type elsewhere.
Why run tsc --noEmit in CI even when a bundler handles the build?
A.Because a bundler cannot read the compiler's configuration file
B.Because a bundler usually only strips types rather than checking them
C.Because a bundler does not fully support TypeScript syntax
D.Because declaration files must be generated for the dependencies
Answer: B
Because fast transpilers like esbuild and swc only strip type information to gain speed; they don't type-check. So the build still succeeds even when the code has type errors. Running the compiler in check-only mode is the only safeguard.
What does function f(...args: [string, number]) mean?
A.The function takes two parameters whose order does not matter
B.The function takes any number of parameters of the two named types
C.The function takes exactly two parameters with the corresponding types by position
D.The function takes one array holding a string and a number as its only argument
Answer: C
The function takes exactly two parameters: the first is a string, the second is a number. A tuple type in the rest position is spread into the parameter list, so calling the function is identical to declaring two ordinary parameters.
A.Allowing both module systems to be mixed in one source file
B.Converting all the output code to ES Module format
C.Allowing CommonJS modules to be imported with default import syntax
D.Automatically converting CommonJS packages to ES Modules on install
Answer: C
It allows importing a CommonJS module using default import syntax. The two module systems have different export models, so without this flag you'd have to use whole-namespace import syntax — which looks odd and doesn't match the docs of most libraries.
A.In a separate package so every part of the system can share them
B.In a separate declaration file to keep them out of the source
C.Beside the code that uses them, exporting only the types in the public API
D.In a shared types file for the whole project
Answer: C
Put them next to the code that uses them, and only export the types that are part of the module's public API. Dumping every type into one shared file makes that file balloon, creates cross-dependencies, and loses the information about which type belongs to which part.
What is the semantic difference between the union string | number and the intersection A & B?
A.A union is one of the types; an intersection satisfies every type at once
B.A union is checked at runtime while an intersection is only checked at compile time
C.A union is broader, so it works everywhere an intersection works
D.A union is only for primitives and an intersection only for objects
Answer: A
A union means the value is one of the types, so you can only use what all members have in common. An intersection means the value satisfies all the types at once, so for objects it merges the properties together.
B.It depends on whether the property was already optional
C.One level only: nested properties stay required
D.Every level, nested objects included
Answer: C
Only one level. It's a mapped type that iterates over the top-level keys and adds the optional marker; it doesn't recurse into nested objects. To affect every level you have to write a recursive type yourself.
B.It raises a compile error if the type passed in could be nullish
C.It guarantees a non-empty value by checking at runtime
D.It marks every property of an object as required
Answer: A
It removes null and undefined from a union while keeping the remaining members. It's useful when you know a value has been checked but the compiler hasn't narrowed it, and when writing utility types that need to drop the empty part.
With const roles = { admin: 1, user: 2 } as const, how do you get the key union?
A.keyof typeof roles
B.keyof roles
C.Object.keys(roles)
D.typeof roles.keys
Answer: A
Use the typeof operator then the keyof operator. The first moves from the value world to the type world, the second produces a union of property names.
A.One lists the fields to keep, the other the fields to drop
B.One works only with interfaces and the other only with type aliases
C.One preserves optionality while the other strips every optional marker
D.One creates a new type while the other edits the original
Answer: A
One lists the fields to keep, the other lists the fields to drop. When the source type gains a new field, the first leaves the result unchanged while the second automatically pulls the new field in.
What does Exclude<Status, "archived"> do to a union?
A.It drops the matching members from the union and keeps the rest
B.It removes the correspondingly named property from an object type
C.It turns the union into an intersection of its members
D.It marks that member as deprecated
Answer: A
It removes the matching members from the union and keeps the rest. The inverse utility keeps the matching members. Both operate on union members, unlike the utility that removes properties from an object.
Getting an existing function return type without redeclaring — what do you use?
A.ReturnType<typeof fn>
B.Assign the result to a variable and take that variable's type
C.Redeclare the result type by hand for clarity
D.Use the parameter-extracting utility and reverse it
Answer: A
Use the return type utility combined with the typeof operator. The type is extracted directly from the function, so it updates automatically when the function changes, instead of having to edit two places and risking drift.
What are template literal types such as `/users/${string}` for?
A.Validating a string with a regular expression on assignment
B.Generating real strings at runtime from the declared pattern
C.Replacing the use of a union of fixed strings
D.Constraining a string to a pattern at compile time
Answer: D
It constrains strings to a pattern at compile time. A string that breaks the pattern is flagged, so typos in paths, event names or config keys are caught early instead of surfacing at runtime.
Modelling loading state as { loading: boolean; data?: T; error?: E } — what is wrong?
A.It permits combinations that cannot occur in reality
B.The optional properties make the type heavier to compile
C.A generic type cannot be reused for several kinds of data
D.It cannot represent the not-yet-started state
Answer: A
It permits impossible combinations: loading and error and data all at once. Code has to defensively check states that never exist, and can still miss a branch that is real.
Importing a JavaScript library errors about missing type declarations. What to do?
A.Turn off the library-checking flag in the configuration
B.Install the type definition package, or write a declaration file yourself
C.Cast the library to any on import
D.Switch to a dynamic import to skip the type check
Answer: B
Install the community-maintained type definitions package, or write a declaration file yourself if there is none. Declaring only the functions you actually use is enough; you do not need to describe the whole library.
Declaring paths in tsconfig for @/components imports requires what else?
A.Renaming the directory to match the declared alias
B.Redeclaring the alias in each file that uses it
C.A matching configuration in the bundler or the runtime
D.Nothing more, because the compiler rewrites the paths itself
Answer: C
Matching configuration in the bundler or runtime. The compiler only uses that declaration for type checking and does not rewrite paths in the emitted code, so the execution environment must know how to resolve them itself.
A.One works at runtime and the other only at compile time
B.One prevents adding new properties, the other prevents editing existing ones
C.One is for arrays and the other for objects
D.One applies to one level of properties, the other locks deeply and preserves literal types
Answer: D
The first only marks the outermost level read-only; the second freezes the whole nested structure and preserves literal types. Both are compile-time constraints and cannot prevent mutation at runtime.
Migrating a large JavaScript project to TypeScript — how to start?
A.Add only declaration files and leave the old code alone
B.Rename every file and fix all the errors at once
C.Rewrite the project from scratch in TypeScript alongside the old one
D.Enable JavaScript files and convert them one at a time
Answer: D
Enable allowing JavaScript files, then convert file by file. Both kinds of files coexist so the team keeps shipping features as normal, and strictness is tightened gradually over time.