Hand-rolled validation

Type guard functions

A type guard is a function that answers one question about an unknown value. Its return type uses the is keyword, so a true result narrows the value inside later code.

One guard checks one fact, such as non empty text or a positive number. Small guards stay obvious, and obvious checks survive refactors without silent drift.

function isNonEmptyString(value: unknown): value is string { return typeof value === "string" && value.length > 0; }

Parse unknown

Server answers arrive typed as unknown until proven otherwise. A parse function inspects the shape field by field and either returns a clean object or throws a clear message.

Never cast first and hope later. Prove each field with a guard, then build the result from proven parts only.

interface User { name: string } function parseUser(value: unknown): User { if (isNonEmptyString(value)) { return { name: value }; } throw new Error("Expected user name text"); }

Collect errors

Throwing on the first problem hides the rest of the form state. Collecting pushes one message per bad field, so the screen can show all fixes at once.

Return an array of strings and treat empty as valid. The caller keeps control: render the list, highlight fields, or proceed when nothing failed.

function checkUser(name: unknown): string[] { const issues: string[] = []; if (!isNonEmptyString(name)) { issues.push("Name must be non empty text"); } return issues; }

Compose guards

Guards compose like building blocks because each one narrows a little further. Combine two simple checks into one named rule instead of repeating long conditions.

Composition keeps error text in one place and intent in one name. Callers read what a value must be, not how every low level test is spelled.

function isName(value: unknown): value is string { return isNonEmptyString(value) && value.length < 80; }

Next: Iterators and generators

Article author: Arthur Isaev

Banner image