41. Order of object keys
What does this print?
const o = { b: 1, 2: 1, a: 1, 1: 1 }
console.log(Object.keys(o))- A.['b', '2', 'a', '1']
- B.['1', '2', 'b', 'a']
- C.['a', 'b', '1', '2']
- D.['b', 'a', '1', '2']
Show answer
Answer: B. ['1', '2', 'b', 'a']
Property order is defined by the spec: integer-like keys come first in ascending numeric order, then string keys in insertion order. So 1 and 2 come first, followed by b and a. If you need a reliable insertion order for any key, including numeric IDs, use a Map.
42. When extra properties are an error
Which line or lines does TypeScript report as an error?
type User = { name: string }
const data = { name: 'Ana', age: 30 }
const a: User = data // line A
const b: User = { name: 'Ana', age: 30 } // line B- A.Both line A and line B
- B.Only line B
- C.Only line A
- D.Neither line, because TypeScript is structurally typed
Show answer
Answer: B. Only line B
TypeScript is structural, so a value with extra properties is still assignable to User, which makes line A fine. But fresh object literals get an extra "excess property check" that flags unknown properties as likely typos, so line B errors. This is why a misspelled option in an inline object is caught, while the same object passed through a variable is not.
43. Symbol keys and JSON
What does this print?
const id = Symbol("id")
const user = { name: "Ravi", [id]: 42 }
console.log(Object.keys(user), JSON.stringify(user))- A.[ "name" ] {"name":"Ravi"}
- B.[ "name", "id" ] {"name":"Ravi","id":42}
- C.[ "name" ] {"name":"Ravi","Symbol(id)":42}
- D.[ "name", "Symbol(id)" ] {"name":"Ravi"}
Show answer
Answer: A. [ "name" ] {"name":"Ravi"}
Symbol-keyed properties are skipped by Object.keys, for...in and JSON.stringify. They can be read with Object.getOwnPropertySymbols or Reflect.ownKeys. This makes symbols useful for metadata that should not leak into serialised data.
44. Object.is and negative zero
What does this print?
console.log(-0 === 0, Object.is(-0, 0), Object.is(NaN, NaN))
- A.true true true
- B.false false true
- C.true false false
- D.true false true
Show answer
Answer: D. true false true
Strict equality treats -0 and +0 as equal and NaN as unequal to itself. Object.is uses the SameValue rule, which separates -0 from +0 and treats NaN as equal to NaN. React uses Object.is to decide whether state has changed.
45. A promise awaited too late
In Node.js, slowTask takes 2 s and failingTask rejects after 100 ms. Why can the process crash with an unhandled rejection?
const a = slowTask()
const b = failingTask()
await a
await b // inside try/catch
- A.await can only be used once in each async function
- B.try/catch does not work with await when running in Node
- C.b rejects while the code still waits on a, with no handler yet
- D.slowTask blocks the whole event loop for the full 2 s
Show answer
Answer: C. b rejects while the code still waits on a, with no handler yet
A rejection is checked for a handler soon after it happens. b rejects at 100 ms, but nothing has attached to b yet because the code is still waiting on a. Node treats it as unhandled and exits. Use await Promise.all([a, b]) so both have handlers at once.
46. Breaking out of for await
An async generator opens a database cursor and closes it in a finally block. What happens when the loop breaks early?
async function* rows() {
const cur = await db.openCursor()
try {
for await (const r of cur) yield r
} finally {
await cur.close()
}
}
for await (const r of rows()) {
if (r.id === 10) break
}- A.break calls return() on the generator, so finally runs
- B.The cursor stays open until garbage collection happens
- C.break throws an error inside the generator body
- D.The loop keeps going until all rows have been read
Show answer
Answer: A. break calls return() on the generator, so finally runs
When a for...of or for await...of loop exits early with break, return or throw, it calls the iterator’s return() method. For a generator this resumes it as if a return happened at the yield, so finally blocks run and resources are released.
47. Progress bar that never moves
This code updates a progress bar 100 times while processing items, but the user only sees 100% at the end. Why?
for (let i = 1; i <= 100; i++) {
processItem(i) // 30 ms of sync work
bar.style.width = i + "%"
}- A.style.width ignores values below 100%
- B.The loop runs too fast for a 60 Hz screen
- C.Percent widths need a transition to show
- D.The browser paints only after the whole task finishes
Show answer
Answer: D. The browser paints only after the whole task finishes
Rendering happens between tasks, not during one. The loop is one long 3-second task, so the browser cannot paint until it ends. Process chunks and yield with await scheduler.yield() or setTimeout so the bar can repaint, or use a Worker.
48. setImmediate inside an I/O callback
In Node.js, what is the order inside a file read callback?
fs.readFile("a.txt", () => {
setTimeout(() => console.log("timeout"), 0)
setImmediate(() => console.log("immediate"))
})- A.immediate, then timeout, every time
- B.timeout, then immediate, every time
- C.It varies between runs
- D.Only immediate is printed
Show answer
Answer: A. immediate, then timeout, every time
After the poll (I/O) phase, Node’s event loop goes to the check phase, where setImmediate callbacks run, before looping back to the timers phase. So inside an I/O callback, immediate always comes first. At the main module top level, the order can vary.
49. Time with a concurrency limit
You upload 100 invoices. Each upload takes 200 ms, and a pool runs at most 5 at a time. Roughly how long does the whole batch take?
- A.20 seconds
- B.200 ms
- C.4 seconds
- D.1 second
Show answer
Answer: C. 4 seconds
With 5 running at once, 100 uploads need 100 ÷ 5 = 20 rounds. Each round takes about 200 ms, so 20 × 200 ms = 4,000 ms. Unlimited Promise.all would start all 100 at once and may hit rate limits or browser connection caps.
50. Promise.resolve of a promise
p is a native promise. What does Promise.resolve(p) === p print?
- A.false
- B.true
- C.undefined
- D.It throws a TypeError
Show answer
Answer: B. true
If the argument is already a native promise created by the same Promise constructor, Promise.resolve returns it unchanged. For other thenables or values it creates a new promise. new Promise(r => r(p)) would always make a new one.
51. Extracting a type with infer
What type does Item resolve to?
type ElementOf<T> = T extends readonly (infer U)[] ? U : never
const cart = [{ sku: "A1", qty: 2 }]
type Item = ElementOf<typeof cart>- A.{ sku: string; qty: number }
- B.{ sku: string; qty: number }[]
- C.never
- D.unknown
Show answer
Answer: A. { sku: string; qty: number }
infer U declares a type variable that TypeScript fills by matching T against the pattern. typeof cart is { sku: string; qty: number }[], which matches an array of U, so U is the object type. Non-array types would give never.
52. Removing optional and readonly
What does this mapped type produce for { readonly id?: string }?
type Mutable<T> = { -readonly [K in keyof T]-?: T[K] }- A.{ readonly id: string }
- B.{ id?: string }
- C.{ id: string }
- D.{ id: string | undefined }
Show answer
Answer: C. { id: string }
In a mapped type, -readonly removes the readonly modifier and -? removes optionality from every property. The built-in Required<T> uses -?, and a + prefix (or none) adds modifiers. The result is a plain required, writable id.
53. What the {} type accepts
Which assignment is a compile error?
let a: {} = 42
let b: {} = "hi"
let c: object = 42
let d: unknown = null- A.Only c
- B.Only a and b
- C.a, b and c
- D.All four
Show answer
Answer: A. Only c
The {} type means "any value except null and undefined", so numbers and strings fit. object means non-primitive values only, so 42 is rejected. unknown accepts everything, including null.
54. Old value after an await
The user types more while save() is running. What does the alert show?
async function handleSave() {
await save(text)
alert("Saved: " + text)
}- A.The text from the render when the click happened
- B.The latest text typed during the save
- C.An empty string
- D.undefined, because state is cleared by await
Show answer
Answer: A. The text from the render when the click happened
The handler closes over text from the render it belongs to. Later renders create new handlers with new text, but this running function still sees its own snapshot. Read the latest value from a ref if you really need it.
55. A custom hook with a stale callback
useCart returns addItem, but addItem always adds to the cart as it was on the first render. What is the bug?
function useCart() {
const [items, setItems] = useState([])
const addItem = useCallback((it) => {
setItems([...items, it])
}, [])
return { items, addItem }
}- A.useCallback must never be used inside custom hooks
- B.items must be stored in a ref instead of in state
- C.It keeps the first items; use setItems((prev) => [...prev, it])
- D.setItems cannot receive arrays, only single items
Show answer
Answer: C. It keeps the first items; use setItems((prev) => [...prev, it])
With an empty dependency array, the callback is created once and keeps the items from the first render. Using the functional update form reads the latest state at update time, so the callback can stay stable without listing items.
56. Removing items while looping forward
This code should remove every cancelled order but leaves one behind for [c, c, ok] (c = cancelled). Why?
for (let i = 0; i < orders.length; i++) {
if (orders[i].cancelled) orders.splice(i, 1)
}- A.splice does not update the array length property
- B.The loop condition is evaluated only once at the start
- C.After splice the next item shifts into index i and is skipped
- D.splice removes two items instead of one here
Show answer
Answer: C. After splice the next item shifts into index i and is skipped
Removing index 0 moves the second cancelled order into index 0, but the loop then increments i to 1 and never checks it. Loop backwards, decrement i after a splice, or better, use filter to build a new array in O(n).
57. NaN and -0 as Map keys
After m.set(NaN, 'a') and m.set(0, 'b'), what do m.get(NaN) and m.get(-0) return?
- A.undefined and 'b'
- B.'a' and undefined
- C.undefined and undefined
- D.'a' and 'b'
Show answer
Answer: D. 'a' and 'b'
Map keys use SameValueZero: NaN is treated as equal to NaN, and +0 and -0 count as the same key. This differs from ===, where NaN !== NaN.
58. Binary search loop that never ends
This search finds the last index where ok(i) is true. When does it loop forever?
while (lo < hi) {
const mid = Math.floor((lo + hi) / 2)
if (ok(mid)) lo = mid
else hi = mid - 1
}- A.When lo and hi are both zero
- B.When ok is false for every index
- C.When hi = lo + 1 and ok(lo) is true
- D.When the array has an even length
Show answer
Answer: C. When hi = lo + 1 and ok(lo) is true
With hi = lo + 1, mid rounds down to lo. If ok(lo) is true, lo = mid changes nothing, and the loop repeats. When the update is lo = mid, round the midpoint up: mid = lo + Math.ceil((hi - lo) / 2).
59. One failure in Promise.all
You fan out three LLM calls in Node.js. What does this code log?
async function call(id) {
if (id === 2) throw new Error('rate limited')
return id * 10
}
const out = []
try {
const r = await Promise.all([1, 2, 3].map(call))
out.push(...r)
} catch (e) {
out.push(e.message)
}
console.log(out)- A.[ 10, 'rate limited', 30 ]
- B.[ 10, 30 ]
- C.[ 10 ]
- D.[ 'rate limited' ]
Show answer
Answer: D. [ 'rate limited' ]
Promise.all rejects as soon as any promise rejects, so r is never assigned and the successful results 10 and 30 are lost; only the error message is pushed. For batch LLM calls, use Promise.allSettled or per-call try/catch with retries so one rate-limit error does not discard the others.
60. Missing the response you wait for
This test sometimes times out even though the request succeeds. Why, and what is the fix?
await page.getByRole('button', { name: 'Search' }).click()
const res = await page.waitForResponse('**/api/search*')
expect(res.ok()).toBeTruthy()- A.waitForResponse only works with POST requests
- B.The glob pattern is invalid
- C.ok() should be status()
- D.The response can arrive before waitForResponse starts listening; start waiting before the click, for example const p = page.waitForResponse(...) then click, then await p
Show answer
Answer: D. The response can arrive before waitForResponse starts listening; start waiting before the click, for example const p = page.waitForResponse(...) then click, then await p
If the API is fast, the response finishes during the click and the listener registered afterwards never sees it. Creating the wait promise first, or using Promise.all with the click, removes the race.