Lesson 12 of 80
A type that describes not just 'a string' but one exact string — the mechanism that turns a specific value into something the compiler can check against, and what narrowing is actually narrowing down to.
10 min read
Every option explains itself — why the right one is right, and why each wrong one is wrong. Miss one and it comes back later on a spaced-repetition schedule.
Question 1 of 2
`let a = "hello";` versus `const b = "hello";` — what type does each get inferred as?
Hints without spoilers, and a plain explanation of why a wrong answer was wrong — answered only from this lesson. Free account, no card.
Sign up freeWhat interviewers actually ask about this, and what a strong answer has to cover.
A strong answer covers
Likely follow-ups
string describes any string. "success" — as a type, not a value — describes exactly one: the string "success" and nothing else.
let status: "success" | "error" | "loading";
status = "success"; // ✅
status = "done"; // ❌ not one of the allowed literals
A union of literal types is how you express "one of these specific, known values" — far more precise than string, and it's what makes exhaustive switch statements and autocomplete for a specific set of values possible.
let x: string = 'GET' — x can be reassigned to ANY string later. Too wide.
let/const inference traplet a = "hello"; // inferred as string (widened) — could be reassigned to anything string-shaped
const b = "hello"; // inferred as "hello" (the literal type) — can never be anything else
TypeScript widens a let's inferred type to the general string/number/boolean, because a let might be reassigned — but a const can't be, so TypeScript keeps the precise literal type. This is exactly why passing an inline object literal's property sometimes needs as const to keep it from widening.
const object — const config = { status: "success" } still infers status: string, not status: "success", because properties of an object are treated as reassignable even if the object binding itself is const. as const is the fix.string.type DiceRoll = 1 | 2 | 3 | 4 | 5 | 6 is a perfectly valid, useful literal union."Why does const config = { status: 'success' } sometimes not narrow the way you'd expect when passed somewhere expecting a literal type?" is a real, common gotcha, and understanding the widening rule (object properties widen regardless of the outer const) is what actually explains it.