Skip to content

Commit

Permalink
Add index signature for passthrough
Browse files Browse the repository at this point in the history
  • Loading branch information
colinhacks committed Mar 4, 2023
1 parent 8074523 commit b6794a4
Show file tree
Hide file tree
Showing 5 changed files with 59 additions and 23 deletions.
13 changes: 11 additions & 2 deletions deno/lib/__tests__/object.test.ts
Expand Up @@ -123,8 +123,8 @@ test("catchall inference", () => {
.catchall(z.number());

const d1 = o1.parse({ first: "asdf", num: 1243 });
util.assertEqual<number, typeof d1["asdf"]>(true);
util.assertEqual<string, typeof d1["first"]>(true);
util.assertEqual<number, (typeof d1)["asdf"]>(true);
util.assertEqual<string, (typeof d1)["first"]>(true);
});

test("catchall overrides strict", () => {
Expand Down Expand Up @@ -442,3 +442,12 @@ test("extend() should have power to override existing key", () => {
{ firstName: string; lastName: number }
>(true);
});

test("passthrough index signature", () => {
const a = z.object({ a: z.string() });
type a = z.infer<typeof a>;
util.assertEqual<{ a: string }, a>(true);
const b = a.passthrough();
type b = z.infer<typeof b>;
util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true);
});
25 changes: 17 additions & 8 deletions deno/lib/types.ts
Expand Up @@ -2127,11 +2127,14 @@ export type baseObjectOutputType<Shape extends ZodRawShape> =

export type objectOutputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam
> = ZodTypeAny extends Catchall
? objectUtil.flatten<baseObjectOutputType<Shape>>
? objectUtil.flatten<baseObjectOutputType<Shape>> & Passthrough<UnknownKeys>
: objectUtil.flatten<
baseObjectOutputType<Shape> & { [k: string]: Catchall["_output"] }
baseObjectOutputType<Shape> & {
[k: string]: Catchall["_output"];
} & Passthrough<UnknownKeys>
>;

export type baseObjectInputType<Shape extends ZodRawShape> = objectUtil.flatten<
Expand All @@ -2140,13 +2143,19 @@ export type baseObjectInputType<Shape extends ZodRawShape> = objectUtil.flatten<
}>
>;

export type Passthrough<UnknownKeys extends UnknownKeysParam> =
UnknownKeys extends "passthrough" ? { [k: string]: unknown } : unknown;

export type objectInputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam
> = ZodTypeAny extends Catchall
? baseObjectInputType<Shape>
? baseObjectInputType<Shape> & Passthrough<UnknownKeys>
: objectUtil.flatten<
baseObjectInputType<Shape> & { [k: string]: Catchall["_input"] }
baseObjectInputType<Shape> & {
[k: string]: Catchall["_input"];
} & Passthrough<UnknownKeys>
>;

export type deoptional<T extends ZodTypeAny> = T extends ZodOptional<infer U>
Expand Down Expand Up @@ -2198,8 +2207,8 @@ export class ZodObject<
T extends ZodRawShape,
UnknownKeys extends UnknownKeysParam = UnknownKeysParam,
Catchall extends ZodTypeAny = ZodTypeAny,
Output = objectOutputType<T, Catchall>,
Input = objectInputType<T, Catchall>
Output = objectOutputType<T, Catchall, UnknownKeys>,
Input = objectInputType<T, Catchall, UnknownKeys>
> extends ZodType<Output, ZodObjectDef<T, UnknownKeys, Catchall>, Input> {
private _cached: { shape: T; keys: string[] } | null = null;

Expand Down
6 changes: 3 additions & 3 deletions playground.ts
@@ -1,4 +1,4 @@
import { z } from "./src";
const px = z.custom<`${number}px`>((val) => /^\d+px$/.test(val as string));
px.parse("100px"); // pass
px.parse("100vw"); // fail

const a = z.object({ a: z.string() }).passthrough();
type a = z.infer<typeof a>;
13 changes: 11 additions & 2 deletions src/__tests__/object.test.ts
Expand Up @@ -122,8 +122,8 @@ test("catchall inference", () => {
.catchall(z.number());

const d1 = o1.parse({ first: "asdf", num: 1243 });
util.assertEqual<number, typeof d1["asdf"]>(true);
util.assertEqual<string, typeof d1["first"]>(true);
util.assertEqual<number, (typeof d1)["asdf"]>(true);
util.assertEqual<string, (typeof d1)["first"]>(true);
});

test("catchall overrides strict", () => {
Expand Down Expand Up @@ -441,3 +441,12 @@ test("extend() should have power to override existing key", () => {
{ firstName: string; lastName: number }
>(true);
});

test("passthrough index signature", () => {
const a = z.object({ a: z.string() });
type a = z.infer<typeof a>;
util.assertEqual<{ a: string }, a>(true);
const b = a.passthrough();
type b = z.infer<typeof b>;
util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true);
});
25 changes: 17 additions & 8 deletions src/types.ts
Expand Up @@ -2127,11 +2127,14 @@ export type baseObjectOutputType<Shape extends ZodRawShape> =

export type objectOutputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam
> = ZodTypeAny extends Catchall
? objectUtil.flatten<baseObjectOutputType<Shape>>
? objectUtil.flatten<baseObjectOutputType<Shape>> & Passthrough<UnknownKeys>
: objectUtil.flatten<
baseObjectOutputType<Shape> & { [k: string]: Catchall["_output"] }
baseObjectOutputType<Shape> & {
[k: string]: Catchall["_output"];
} & Passthrough<UnknownKeys>
>;

export type baseObjectInputType<Shape extends ZodRawShape> = objectUtil.flatten<
Expand All @@ -2140,13 +2143,19 @@ export type baseObjectInputType<Shape extends ZodRawShape> = objectUtil.flatten<
}>
>;

export type Passthrough<UnknownKeys extends UnknownKeysParam> =
UnknownKeys extends "passthrough" ? { [k: string]: unknown } : unknown;

export type objectInputType<
Shape extends ZodRawShape,
Catchall extends ZodTypeAny
Catchall extends ZodTypeAny,
UnknownKeys extends UnknownKeysParam
> = ZodTypeAny extends Catchall
? baseObjectInputType<Shape>
? baseObjectInputType<Shape> & Passthrough<UnknownKeys>
: objectUtil.flatten<
baseObjectInputType<Shape> & { [k: string]: Catchall["_input"] }
baseObjectInputType<Shape> & {
[k: string]: Catchall["_input"];
} & Passthrough<UnknownKeys>
>;

export type deoptional<T extends ZodTypeAny> = T extends ZodOptional<infer U>
Expand Down Expand Up @@ -2198,8 +2207,8 @@ export class ZodObject<
T extends ZodRawShape,
UnknownKeys extends UnknownKeysParam = UnknownKeysParam,
Catchall extends ZodTypeAny = ZodTypeAny,
Output = objectOutputType<T, Catchall>,
Input = objectInputType<T, Catchall>
Output = objectOutputType<T, Catchall, UnknownKeys>,
Input = objectInputType<T, Catchall, UnknownKeys>
> extends ZodType<Output, ZodObjectDef<T, UnknownKeys, Catchall>, Input> {
private _cached: { shape: T; keys: string[] } | null = null;

Expand Down

0 comments on commit b6794a4

Please sign in to comment.