When Assertions Are Dangerous

Assertions Hide Bugs

Example

The API actually sent price as a string. The assertion said it was a number, so TypeScript did not complain and the total became a joined string.

type Product = { name: string; price: number };

const fromApi = JSON.parse('[{"name": "Pen", "price": "20"}, {"name": "Book", "price": "150"}]') as Product[];

let total = 0;
for (const p of fromApi) total += p.price;
console.log(total);

Output

020150

Safer Options

  • Check at runtime with typeof, in, Array.isArray or a type guard function.
  • Use a validation library (Zod, Valibot) for API data. You will build a mini version in the advanced level.
  • Use satisfies (medium level) when you want checking without changing the type.
  • Prefer ?. and ?? over ! for possibly missing values.

Example

The same data, converted and checked instead of asserted:

type Product = { name: string; price: number };

function toProduct(x: unknown): Product {
  if (typeof x !== "object" || x === null || !("name" in x) || !("price" in x)) {
    throw new Error("Invalid product");
  }
  const price = Number(x.price);
  if (Number.isNaN(price)) throw new Error("Invalid price");
  return { name: String(x.name), price };
}

const data: unknown[] = JSON.parse('[{"name": "Pen", "price": "20"}, {"name": "Book", "price": "150"}]');
const products = data.map(toProduct);
console.log(products.reduce((s, p) => s + p.price, 0));

Output

170