2.5 KiB
strip-undefined
Purpose
stripUndefined is a route-layer adapter that bridges Zod's
optional() output (T | undefined) with the
exactOptionalPropertyTypes: true repository input types declared in
@suaveplan/campaigns and the local CampaignSuppressionStore. When a
route handler validates a request body through a Zod schema, optional
fields surface as either the declared type or undefined; passing the
parsed object straight to the repository fails the exactOptional
check at compile time. This helper produces a shallow clone with every
undefined-valued key removed so the downstream type narrows.
The helper is intentionally minimal — no recursion, no null handling,
no key-name filtering — because every concrete usage in the routes
layer passes a Zod-parsed object whose nesting has already been
normalised. Recursion would obscure the cost model and tempt callers
to use it as a deep-clean utility, which is out of scope.
Features
- Shallow-only filter; nested objects are forwarded by reference.
nullvalues are preserved (only=== undefinedtriggers removal).- Returns a fresh object reference every call (never mutates input).
- Generic-typed return narrows
T[K]toExclude<T[K], undefined>.
Usage: Basic
import { stripUndefined } from "@suaveplan/api-plugin-campaigns";
const body = { name: "x", templateId: undefined } as const;
const clean = stripUndefined(body);
// clean: { name: "x" } — `templateId` removed.
Usage: Advanced
import { stripUndefined } from "@suaveplan/api-plugin-campaigns";
const parsed = CreateCampaignSchema.parse(input);
await repo.create({
id: idGen(),
tenantId,
...stripUndefined(parsed),
status: "draft",
stats: EMPTY_STATS,
createdAt: now,
updatedAt: now,
});
API Reference
stripUndefined<T extends Record<string, unknown>>(input: T): { [K in keyof T]: Exclude<T[K], undefined> }— shallow copy withundefined-valued keys removed.
Implementation Notes
The implementation iterates Object.entries(input) once and writes
into a fresh Record<string, unknown> accumulator. The output is then
cast to the narrowed mapped type — a single assertion confined to the
return statement. The accumulator is not pre-sized because the helper
is hot-path-cheap (single object scan) and JavaScript engines do not
benefit from new Object() capacity hints. The forbidden Object.assign
path (which would forward undefined properties when iterating
Object.keys) is intentionally avoided.