Skip to content
Chapter 4Lesson 9

Quiz - Typing values you know

Quiz progress

0 / 0

A webhook handler receives a payload whose shape isn’t known at compile time. Two engineers reach for different annotations:

const handleA = (payload: any) => payload.user.email;
const handleB = (payload: unknown) => payload.user.email;

Which best describes the operational difference between the two?

They are equivalent — both compile, and only handleB errors at runtime.
handleA compiles and may crash at runtime; handleB fails at compile time until the value is narrowed.
handleB compiles but disables type-checking on payload; handleA requires narrowing before any read.

The course defaults to type for every alias. Which scenario is the one trigger that earns a reach for interface instead?

Composing a request payload from a base shape and a route-specific extension.
Augmenting a third-party type (for example Better Auth’s Session) inside a declare module block.
Declaring an object shape whose fields might later need optional or readonly modifiers.

useState returns [value, setter] instead of { value, setValue }. What’s the senior reason the tuple shape wins here?

A tuple is faster at runtime than a named-field object.
The caller destructures-and-renames on every use, so the positional shape carries no naming penalty — each call site picks the names it wants.
TypeScript can’t infer object property types from generic hooks, so a tuple is the only shape that works.

You’re typing a lookup table from invoice status to display label. The status is 'draft' | 'sent' | 'paid'. Under noUncheckedIndexedAccess, which type catches a missing key at the literal site and reads back as string (not string | undefined)?

Record<string, string>
{ [status: string]: string }
Record<'draft' | 'sent' | 'paid', string>

A function takes value: User | Guest. User has an email field; Guest doesn’t. You need to read email when it exists. Which moves are correct senior reflexes? Select all that apply.

Narrow with if ('email' in value) before the read.
Widen the parameter to { email?: string; name: string } so the read compiles.
Write (value as User).email — you know the call sites only pass users with emails.
Add a literal-typed discriminant to each variant and switch on it.

Which of the following is not one of the three legitimate triggers for reaching for as?

A userSchema.parse(raw) boundary where the parser validates unknown and returns a typed value.
A document.querySelector('button[type="submit"]') as HTMLButtonElement in a tightly-scoped one-shot.
Casting a User | Guest parameter to User because most call sites pass users.
A cache.get(id) as User immediately after cache.set(id, user), where the type system can’t track the round-trip.

Consider the four scenarios below. Which calls for the combined as const satisfies T idiom?

The signature of an exported function — (input: { email: string }) => void.
A module-level routes map whose keys must cover every RouteName and whose values must remain literal paths so (typeof ROUTES)[keyof typeof ROUTES] narrows.
A local variable holding the result of a reduce over a list of numbers.

Which line is the wrong reach under the boundary rule and verbatimModuleSyntax?

const total = items.reduce((acc, item) => acc + item.price, 0);
export const createInvoice = async (
input: CreateInvoiceInput,
): Promise<Result<Invoice>> => { /* ... */ };
import { User } from './user';
const greet = (user: User) => `Hello, ${user.name}`;

Quiz complete

Score by topic