Skip to content
Sarj Code Standards

no-runtime-typeof

Prefer Zod boundary schemas or discriminated unions over runtime typeof checks.

Why

Representation checks spread value contracts across control flow. Specific boundary schemas and discriminated unions keep validation and the inferred application contract together.

Fix

Parse external structured input with a specific Zod schema, or model owned variants with a discriminated union. Required raw preprocessors, field-independent utilities, arbitrary metadata walkers and framework primitive unions need an exact-code local suppression explaining their contract.

Examples

Before — flagged Read a declared value directly when checking undefined
src/environment.ts
function missing(value: unknown) {
return typeof value === "undefined";
}
After — preferred Probe a potentially absent global without reading it
src/environment.ts
const isServer = typeof document === "undefined";
Before — flagged Give owned variants a domain discriminator
src/value.ts
function render(value: string | number) {
return typeof value === "string" ? value : value.toString();
}
After — preferred Branch on an owned domain discriminator
src/value.ts
type Value = { kind: "text"; value: string } | { kind: "count"; value: number };
function render(value: Value) {
return value.kind === "text" ? value.value : value.value.toString();
}
Before — flagged Keep a type query out of executable code
src/value.ts
declare const value: { id: string };
const kind = typeof value;
After — preferred Preserve the erased TypeScript type query
src/value.ts
declare const value: { id: string };
type Value = typeof value;
Before — flagged Replace a representation check with an explicit contract
src/input.ts
function parse(value: unknown) {
if (
typeof value === "object" &&
value !== null &&
!Array.isArray(value) &&
"id" in value &&
typeof value.id === "string"
)
return { id: value.id };
throw new Error("Expected a record with a text id");
}
After — preferred Validate consumed fields at their boundary
src/input.ts
import { z } from "zod";
const UserSchema = z.object({ id: z.string() });
function parse(value: unknown) {
return UserSchema.parse(value);
}

References