Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 16 additions & 0 deletions deno/lib/__tests__/generics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -23,3 +23,19 @@ test("generics", () => {
const result = stripOuter(z.object({ a: z.string() }), { a: "asdf" });
util.assertEqual<typeof result, Promise<{ a: string }>>(true);
});

test("assignability", () => {
const createSchemaAndParse = <K extends string, VS extends z.ZodString>(
key: K,
valueSchema: VS,
data: unknown
) => {
const schema = z.object({
[key]: valueSchema,
});
const parsed = schema.parse(data);
const inferred: z.infer<z.ZodObject<{ [k in K]: VS }>> = parsed;
return inferred;
};
createSchemaAndParse("foo", z.string(), { foo: "" });
});
20 changes: 20 additions & 0 deletions deno/lib/__tests__/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -451,3 +451,23 @@ test("passthrough index signature", () => {
type b = z.infer<typeof b>;
util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true);
});

test("xor", () => {
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T extends object
? U extends object
? (Without<T, U> & U) | (Without<U, T> & T)
: U
: T;

type A = { name: string; a: number };
type B = { name: string; b: number };
type C = XOR<A, B>;
type Outer = { data: C };
const Outer: z.ZodType<Outer> = z.object({
data: z.union([
z.object({ name: z.string(), a: z.number() }),
z.object({ name: z.string(), b: z.number() }),
]),
});
});
15 changes: 10 additions & 5 deletions deno/lib/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,23 @@ export namespace objectUtil {
[k in Exclude<keyof U, keyof V>]: U[k];
} & V;

// type optionalKeys<T extends object> = {
// [k in keyof T]: undefined extends T[k] ? k : never;
// }[keyof T];
type optionalKeys<T extends object> = {
[k in keyof T]: undefined extends T[k] ? k : never;
}[keyof T];

type requiredKeys<T extends object> = {
[k in keyof T]: undefined extends T[k] ? never : k;
}[keyof T];

// export type addQuestionMarks<
// T extends object,
// R extends keyof T = requiredKeys<T>
// > = Pick<Required<T>, R> & Partial<T>;
export type addQuestionMarks<
T extends object,
R extends keyof T = requiredKeys<T>
> = Pick<Required<T>, R> & Partial<T>;
R extends keyof T = requiredKeys<T>,
O extends keyof T = optionalKeys<T>
> = Pick<T, R> & Partial<Pick<T, O>> & { [k in keyof T]?: unknown };

export type identity<T> = T;
export type flatten<T> = identity<{ [k in keyof T]: T[k] }>;
Expand Down
5 changes: 1 addition & 4 deletions playground.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,3 @@
import { z, ZodNativeEnum } from "./src";
import { z } from "./src";

z;

const A = z.object({}).catchall(z.string());
type A = z.infer<typeof A>;
16 changes: 16 additions & 0 deletions src/__tests__/generics.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -22,3 +22,19 @@ test("generics", () => {
const result = stripOuter(z.object({ a: z.string() }), { a: "asdf" });
util.assertEqual<typeof result, Promise<{ a: string }>>(true);
});

test("assignability", () => {
const createSchemaAndParse = <K extends string, VS extends z.ZodString>(
key: K,
valueSchema: VS,
data: unknown
) => {
const schema = z.object({
[key]: valueSchema,
});
const parsed = schema.parse(data);
const inferred: z.infer<z.ZodObject<{ [k in K]: VS }>> = parsed;
return inferred;
};
createSchemaAndParse("foo", z.string(), { foo: "" });
});
20 changes: 20 additions & 0 deletions src/__tests__/object.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -450,3 +450,23 @@ test("passthrough index signature", () => {
type b = z.infer<typeof b>;
util.assertEqual<{ a: string } & { [k: string]: unknown }, b>(true);
});

test("xor", () => {
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T extends object
? U extends object
? (Without<T, U> & U) | (Without<U, T> & T)
: U
: T;

type A = { name: string; a: number };
type B = { name: string; b: number };
type C = XOR<A, B>;
type Outer = { data: C };
const Outer: z.ZodType<Outer> = z.object({
data: z.union([
z.object({ name: z.string(), a: z.number() }),
z.object({ name: z.string(), b: z.number() }),
]),
});
});
15 changes: 10 additions & 5 deletions src/helpers/util.ts
Original file line number Diff line number Diff line change
Expand Up @@ -100,18 +100,23 @@ export namespace objectUtil {
[k in Exclude<keyof U, keyof V>]: U[k];
} & V;

// type optionalKeys<T extends object> = {
// [k in keyof T]: undefined extends T[k] ? k : never;
// }[keyof T];
type optionalKeys<T extends object> = {
[k in keyof T]: undefined extends T[k] ? k : never;
}[keyof T];

type requiredKeys<T extends object> = {
[k in keyof T]: undefined extends T[k] ? never : k;
}[keyof T];

// export type addQuestionMarks<
// T extends object,
// R extends keyof T = requiredKeys<T>
// > = Pick<Required<T>, R> & Partial<T>;
export type addQuestionMarks<
T extends object,
R extends keyof T = requiredKeys<T>
> = Pick<Required<T>, R> & Partial<T>;
R extends keyof T = requiredKeys<T>,
O extends keyof T = optionalKeys<T>
> = Pick<T, R> & Partial<Pick<T, O>> & { [k in keyof T]?: unknown };

export type identity<T> = T;
export type flatten<T> = identity<{ [k in keyof T]: T[k] }>;
Expand Down