CodeOath
← All posts
TypeScript75 min total · 21 parts

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

Contents — Part 17 of 21: Type Assertions and Non-null Assertion
Part 17 of 21 · ~1 min

Type Assertions and Non-null Assertion

A type assertion (as) tells the compiler "trust me, treat this value as this type" without any actual runtime check or conversion — it is not a cast in the C#/Java sense:

const input = document.getElementById("email") as HTMLInputElement;
input.value; // compiles — but only actually safe if the element really is an <input>

const value = "42" as unknown as number;
// forcing an assertion through `unknown` bypasses TypeScript's normal check that the
// two types must overlap — a strong signal this code deserves a second look

The non-null assertion operator (!) tells the compiler a value that's typed as possibly null/undefined definitely isn't, at this specific point:

function getElement(id: string): HTMLElement | null {
  return document.getElementById(id);
}

const el = getElement("app")!; // asserts it's not null — no runtime check happens
el.textContent = "Hello";      // if getElement actually returned null, this throws at runtime

Both operators are compile-time-only promises with zero runtime effect — if the assertion is wrong, TypeScript doesn't catch it, and the mistake surfaces as an ordinary runtime error (often a confusing one, since the surrounding code was written as if the type were guaranteed). They're occasionally necessary — working with the DOM, or narrowing a case the compiler genuinely can't infer — but reaching for as/! to silence an error instead of fixing the underlying type mismatch is one of the most common ways real codebases quietly lose the safety TypeScript is supposed to provide.