# `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. - `null` values are preserved (only `=== undefined` triggers removal). - Returns a fresh object reference every call (never mutates input). - Generic-typed return narrows `T[K]` to `Exclude`. ## Usage: Basic ```ts 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 ```ts 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>(input: T): { [K in keyof T]: Exclude }` — shallow copy with `undefined`-valued keys removed. ## Implementation Notes The implementation iterates `Object.entries(input)` once and writes into a fresh `Record` 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.