Skip to main content
CodeOath
← All posts

TypeScript63 min total · 21 parts

TypeScript Fundamentals: Types, Interfaces, Generics, and Why It Catches Bugs Before Runtime

Part 17 of 21 · ~2 min

Type Assertions and Non-null Assertion

as tells TypeScript to stop checking a value's type against what it can actually prove, and just accept the type you're claiming instead. Nothing runs because of it — no conversion, no validation, not even a comment in the compiled output:

const resumeFrame = document.getElementById("resume-frame") as HTMLIFrameElement;
const resumeUrl = getResumeUrl(applicant.id);
resumeFrame.src = resumeUrl; // compiles regardless of whether the element is actually an iframe

const rawScore = "87" as unknown as number;
// a string and a number don't overlap enough for TS to allow a direct "as" between them —
// routing the assertion through `unknown` first is how you force it anyway

The non-null assertion, !, makes a narrower and more specific claim: that a value which could in principle be null or undefined isn't, at this exact spot in the code:

function reviewNext(queue: ApplicationQueue) {
  if (queue.size === 0) return;
  const next = queue.dequeue()!; // we just proved size > 0, so this genuinely can't be undefined
  console.log(next.name);        // but if it somehow were, this is exactly where it would throw
}

Both of these are promises made to the compiler with nothing behind them at runtime — get one wrong, and TypeScript has no way to notice, because by design it stopped checking the moment you wrote as or !. The failure doesn't disappear; it just relocates, to some ordinary-looking runtime error later on, in code that was written as though the guarantee actually held. There are places both are genuinely the right tool — the DOM cast above, or the size check that makes the non-null assertion provably safe right where it's used — but reaching for either one purely to make a red squiggle go away, instead of fixing whatever the compiler was actually flagging, is one of the more common ways a TypeScript codebase slowly loses the protection it was adopted for in the first place. The double assertion through unknown is the sharpest version of this risk, precisely because it exists to force through a conversion TypeScript would otherwise refuse — which makes it a place to slow down, not a shortcut, especially anywhere near a webhook payload, which is the exact boundary the previous chapter flagged.