From 4a193d9801122f5b616ab7c16a77df1067260372 Mon Sep 17 00:00:00 2001 From: Vitaly Budovski Date: Wed, 25 Dec 2024 18:39:38 +1100 Subject: [PATCH] feature: Object omit --- .../reference/Schema/Collections/object.mdx | 20 +++++++++++++++++++ paseri-lib/src/schemas/object.test.ts | 14 +++++++++++++ paseri-lib/src/schemas/object.ts | 12 ++++++++++- 3 files changed, 45 insertions(+), 1 deletion(-) diff --git a/paseri-docs/src/content/docs/reference/Schema/Collections/object.mdx b/paseri-docs/src/content/docs/reference/Schema/Collections/object.mdx index 98dd18a..fc48e03 100644 --- a/paseri-docs/src/content/docs/reference/Schema/Collections/object.mdx +++ b/paseri-docs/src/content/docs/reference/Schema/Collections/object.mdx @@ -154,3 +154,23 @@ p.object({ }); */ ``` + +### `omit` + +Analogous to TypeScript's built-in `Omit` utility type. Creates a schema that contains all except the selected keys. + +```typescript +import * as p from '@vbudovski/paseri'; + +const schema = p.object({ + foo: p.string(), + bar: p.number(), +}); +const schemaOmitted = schema.omit('foo'); +/* +The resulting schema will be: +p.object({ + bar: p.number(), +}); +*/ +``` diff --git a/paseri-lib/src/schemas/object.test.ts b/paseri-lib/src/schemas/object.test.ts index d9b24e0..884a06f 100644 --- a/paseri-lib/src/schemas/object.test.ts +++ b/paseri-lib/src/schemas/object.test.ts @@ -393,3 +393,17 @@ test('Pick', () => { expect(result.ok).toBeTruthy(); } }); + +test('Omit', () => { + const schema = p.object({ foo: p.string(), bar: p.number() }); + const schemaOmitted = schema.omit('foo'); + + const data = { bar: 123 }; + const result = schemaOmitted.safeParse(data); + if (result.ok) { + expectTypeOf(result.value).toEqualTypeOf<{ bar: number }>; + expect(result.value).toEqual(data); + } else { + expect(result.ok).toBeTruthy(); + } +}); diff --git a/paseri-lib/src/schemas/object.ts b/paseri-lib/src/schemas/object.ts index d2d813b..01cb26b 100644 --- a/paseri-lib/src/schemas/object.ts +++ b/paseri-lib/src/schemas/object.ts @@ -1,4 +1,4 @@ -import type { Merge, NonEmptyObject, TupleToUnion } from 'type-fest'; +import type { IsEqual, Merge, NonEmptyObject, TupleToUnion } from 'type-fest'; import type { Infer } from '../infer.ts'; import { type LeafNode, type TreeNode, issueCodes } from '../issue.ts'; import { addIssue } from '../issue.ts'; @@ -184,6 +184,16 @@ class ObjectSchema> extends Schema keys.includes(key as keyof ShapeType))), ); } + omit( + // Ensure at least one key remains in schema. + ...keys: IsEqual, keyof ShapeType> extends true ? never : Keys + // @ts-expect-error FIXME: How do we get the shape validation to play nicely with Omit? + ): ObjectSchema>> { + // @ts-expect-error FIXME: How do we get the shape validation to play nicely with Omit? + return new ObjectSchema>>( + Object.fromEntries(this._shape.entries().filter(([key]) => !keys.includes(key as keyof ShapeType))), + ); + } } function object>(