12. unknown versus any
Why is unknown often a better type than any for data like a parsed API response?
const data: unknown = JSON.parse(text)
data.user.name // compile error
- A.unknown forces you to narrow or validate the value before using it, while any turns off type checking
- B.unknown makes the code run faster in the browser than any
- C.unknown automatically validates the JSON at runtime
- D.unknown lets you call any property without errors, like any, but with better autocomplete
Show answer
Answer: A. unknown forces you to narrow or validate the value before using it, while any turns off type checking
With any, every property access and call is allowed, so mistakes reach production silently. With unknown, TypeScript refuses to use the value until you check it, for example with typeof, in, or a schema parser. Neither type exists at runtime; the gain is safety at compile time.
13. Constraining a generic
Which call is a compile-time error?
function longest<T extends { length: number }>(a: T, b: T) {
return a.length >= b.length ? a : b
}- A.longest("Delhi", "Dubai")
- B.longest([1, 2], [3])
- C.longest(10, 20)
- D.longest({ length: 2 }, { length: 5 })
Show answer
Answer: C. longest(10, 20)
T extends { length: number } means T must have a numeric length property. Strings, arrays and objects with length fit, but numbers do not. The constraint also lets the function body read a.length safely.
14. Type for a PATCH body
A PATCH /users/:id endpoint accepts any subset of name, email and phone, but never id. Given type User = { id: string; name: string; email: string; phone: string }, which type fits?
- A.Pick<User, "id">
- B.Required<User>
- C.Omit<Partial<User>, "name">
- D.Partial<Omit<User, "id">>
Show answer
Answer: D. Partial<Omit<User, "id">>
Omit<User, "id"> removes id, and Partial makes every remaining field optional. Pick would keep only id, and Required would force every field. Combining utility types like this avoids writing a second hand-made type.
15. A function that narrows a type
What does the return type value is ApiError do here?
function isApiError(value: unknown): value is ApiError {
return typeof value === "object" && value !== null && "code" in value
}- A.It checks the shape of ApiError at runtime automatically
- B.It casts value to ApiError for the whole function
- C.It makes the function return an ApiError object
- D.In an if (isApiError(x)) block, x is narrowed to ApiError
Show answer
Answer: D. In an if (isApiError(x)) block, x is narrowed to ApiError
A type predicate tells TypeScript that when the function returns true, the argument is that type. The check itself is your own code, so if it is wrong TypeScript will still trust it. Use it to narrow unknown data safely.
16. Narrowing with the in operator
type Admin = { permissions: string[] } and type Guest = { expiresAt: Date }. In if ("permissions" in user) { ... }, what is user narrowed to?
- A.Admin
- B.Guest
- C.Admin | Guest
- D.never
Show answer
Answer: A. Admin
The in operator narrows a union to the members that have (or may have) that property. Only Admin declares permissions, so inside the if user is Admin, and in the else branch it is Guest.
17. Reusing a function’s return type
You want a type for whatever buildInvoice() returns, without writing it by hand. Which is correct?
- A.type Invoice = ReturnType<typeof buildInvoice>
- B.type Invoice = ReturnType<buildInvoice>
- C.type Invoice = typeof buildInvoice()
- D.type Invoice = buildInvoice["return"]
Show answer
Answer: A. type Invoice = ReturnType<typeof buildInvoice>
ReturnType needs a function type, and typeof buildInvoice turns the value into its type. Passing buildInvoice directly fails because it is a value, not a type. For async functions, wrap it as Awaited<ReturnType<typeof fn>>.
18. One schema for form and API
In a TypeScript monorepo you define a Zod schema for "create project" and import it in both the React form and the API route. Which statement is true?
- A.Once the form has validated, the API can safely trust the body and skip parsing it again
- B.Zod only works in the browser, so the API needs a different library
- C.The API still parses with the schema; sharing keeps rules and types in sync
- D.Sharing the schema exposes your database structure to attackers
Show answer
Answer: C. The API still parses with the schema; sharing keeps rules and types in sync
Client validation improves the experience but anyone can bypass it, so the server parses again with the same schema. Sharing it means error messages, limits and the z.infer types never drift between tiers. The schema describes input shape, not secrets, so shipping it to the browser is fine.
19. Catch-all versus optional catch-all
A docs site uses app/docs/[...slug]/page.tsx. What does a visit to /docs (with no further path) give?
- A.The page, with slug as an empty array
- B.The page, with slug undefined
- C.A redirect to /docs/index
- D.A 404, since [...slug] needs one segment or more
Show answer
Answer: D. A 404, since [...slug] needs one segment or more
A catch-all [...slug] matches /docs/a, /docs/a/b and so on, but not /docs itself. The optional catch-all [[...slug]] also matches /docs, with slug undefined.
20. Error in a layout not caught
app/dashboard/layout.tsx throws an error. Why does app/dashboard/error.tsx not catch it?
- A.error.tsx only catches errors in route handlers
- B.error.tsx wraps that segment's children, not its layout
- C.Layouts never throw errors in production
- D.The error.tsx file must be in the pages folder
Show answer
Answer: B. error.tsx wraps that segment's children, not its layout
In the hierarchy, a segment's error boundary sits inside its layout. So an error in the layout bubbles up to the parent segment's error.tsx, or to global-error.tsx for the root layout.
21. Error in the root layout
What handles an error thrown in app/layout.tsx?
- A.app/global-error.tsx, which must render html and body
- B.app/error.tsx in the same folder as the layout
- C.app/not-found.tsx in the same folder
- D.Nothing; the server crashes in production
Show answer
Answer: A. app/global-error.tsx, which must render html and body
Since the root layout is the top, only global-error.tsx can catch its errors. It replaces the root layout when active, so it must include its own html and body tags.
22. Is proxy enough for auth?
Is a cookie check in proxy.ts enough to protect a dashboard and its Server Actions?
- A.Yes; proxy runs before every possible request
- B.No; also check auth where data is read or changed
- C.Yes; Server Actions skip proxy and are safe
- D.No; proxy cannot read cookies at all
Show answer
Answer: B. No; also check auth where data is read or changed
Proxy is good for quick redirects, but matchers can miss paths and config can change. Check the session close to the data, in Server Components, route handlers and every Server Action.