Lesson 27 of 80
The compiler flag that made `null`/`undefined` unassignable to every other type by default — and the `!` operator that lets you locally override it, at your own risk.
11 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
`const user = getUser("1"); user!.name;` — if getUser actually returns undefined here, what happens at runtime?
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
With strictNullChecks enabled (part of strict: true, and effectively the modern default), null and undefined are not automatically part of every type — let name: string genuinely cannot be null unless the type explicitly says string | null.
function getUser(id: string): User | undefined { /* ... */ }
const user = getUser("1");
user.name; // ❌ user might be undefined — compiler blocks this
user!.name; // ✅ compiles — "I promise this isn't undefined, trust me"
The ! (non-null assertion operator) is the narrowest possible escape hatch: it tells the compiler "treat this specific expression as non-nullable here," with zero runtime check — if you're wrong, user really is undefined, and user!.name throws a real TypeError at runtime, exactly as if the ! weren't there.
function find(id: string): User | undefined — the return type honestly admits it might not find anything.
! is a type assertion, not a null check. It performs no runtime validation at all — it's purely a compiler instruction, in the same family as as, just specifically for stripping null/undefined from a type.if (user)) or a default (user ?? fallback) over ! whenever possible — both are real, verified-by-the-compiler-and-checked-at-runtime approaches; ! is a promise you're making, not a fact the compiler verified.strictNullChecks changes what null/undefined mean everywhere — a codebase migrating into strict mode typically surfaces dozens of real, previously-invisible null-handling bugs the moment it's turned on, which is exactly the point."When is it actually okay to use !?" tests judgment, not just syntax — the strong answer is "rarely, and only when you have information the compiler genuinely can't have (e.g., immediately after a runtime check the type system can't see)," not "whenever the compiler complains."