Initial Commit
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
# routes/shared/strip-undefined — drop undefined-valued keys
|
||||
|
||||
## Purpose
|
||||
|
||||
Bridges Zod's optional-field semantics
|
||||
(`.optional() → string | undefined`) with the suaveplan
|
||||
`@suaveplan/contacts` input shapes, which use
|
||||
`exactOptionalPropertyTypes: true` and therefore forbid the
|
||||
`| undefined` half of optional members. Returning a shallow copy with
|
||||
`undefined` keys removed lets the route handlers feed Zod output
|
||||
directly into `repo.create({ ...stripUndefined(parsed.data), tenantId })`
|
||||
without losing type safety.
|
||||
|
||||
Without this helper every route handler would need to manually
|
||||
re-build the input object key-by-key, or every Zod schema would have
|
||||
to redefine its optionality via `.transform()`. The helper is the
|
||||
focused fix.
|
||||
|
||||
## Features
|
||||
|
||||
- Shallow — preserves nested undefineds because the consumer Zod
|
||||
schemas only produce top-level optionals.
|
||||
- Preserves `null`, `0`, `""`, and `false` (only `undefined` is dropped).
|
||||
- Pure / type-safe — returns `Partial<T>`-compatible shape.
|
||||
|
||||
## Usage: Basic
|
||||
|
||||
```ts
|
||||
import { stripUndefined } from "@suaveplan/api-plugin-contacts";
|
||||
|
||||
const parsed = CreateContactSchema.parse(input);
|
||||
const repoInput = stripUndefined(parsed);
|
||||
await repo.create({ ...repoInput, tenantId });
|
||||
```
|
||||
|
||||
## Usage: Advanced
|
||||
|
||||
```ts
|
||||
import { stripUndefined } from "@suaveplan/api-plugin-contacts";
|
||||
|
||||
function safeMerge<T extends Record<string, unknown>>(base: T, patch: Partial<T>): T {
|
||||
return { ...base, ...stripUndefined(patch) } as T;
|
||||
}
|
||||
```
|
||||
|
||||
## API Reference
|
||||
|
||||
- `stripUndefined<T>(input: T): { [K in keyof T]?: T[K] }` — shallow
|
||||
copy with `undefined` keys omitted.
|
||||
|
||||
## Implementation Notes
|
||||
|
||||
- Uses `Object.entries` so symbol-keyed properties are ignored; route
|
||||
inputs are always plain objects so this is fine.
|
||||
- Does not deep-clone — the returned object shares nested references
|
||||
with the input.
|
||||
- The return type widens to `Partial<T>` for ergonomics; the runtime
|
||||
contract is stricter (any non-`undefined` original value flows
|
||||
through unchanged).
|
||||
Reference in New Issue
Block a user