Skip to content

Commit

Permalink
feat(guard) reintroduce check as guard
Browse files Browse the repository at this point in the history
discussion: unlike check, guard is only visible when Output extend Input
  • Loading branch information
oberbeck committed Nov 19, 2024
1 parent 2aa0a47 commit 47f04a9
Show file tree
Hide file tree
Showing 4 changed files with 72 additions and 0 deletions.
29 changes: 29 additions & 0 deletions deno/lib/__tests__/guard.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, expectTypeOf, test } from "vitest";
import { z } from "../index.ts";

describe("guard", () => {
test("work as a type guard when Output extends Input", () => {
expectTypeOf<true>().toEqualTypeOf<true>();
});
test("work as a type guard when Output *does* extend Input", () => {
const inputExtendsOutputSchema = z.object({
a: z.string(),
b: z.enum(["x", "y"]).transform((arg) => arg as string),
});
const val = null as unknown;
if (inputExtendsOutputSchema.guard(val)) {
expectTypeOf(val).toEqualTypeOf<{ a: string; b: string }>();
} else {
expectTypeOf(val).toEqualTypeOf<unknown>();
}
});

test("to be unavailable when Output *does not* extend Input", () => {
const inputDiffersFromOutputSchema = z
.string()
.transform((arg) => parseFloat(arg));
const val = null as unknown;
// @ts-expect-error - compile error as Input does not extend Output
inputDiffersFromOutputSchema.guard(val);
});
});
7 changes: 7 additions & 0 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,13 @@ export abstract class ZodType<
isNullable(): boolean {
return this.safeParse(null).success;
}

guard<T extends Output>(
this: ZodType<T, any, T>,
data: unknown
): data is Output {
return this.safeParse(data).success;
}
}

/////////////////////////////////////////
Expand Down
29 changes: 29 additions & 0 deletions src/__tests__/guard.test-d.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
import { describe, expectTypeOf, test } from "vitest";
import { z } from "../index";

describe("guard", () => {
test("work as a type guard when Output extends Input", () => {
expectTypeOf<true>().toEqualTypeOf<true>();
});
test("work as a type guard when Output *does* extend Input", () => {
const inputExtendsOutputSchema = z.object({
a: z.string(),
b: z.enum(["x", "y"]).transform((arg) => arg as string),
});
const val = null as unknown;
if (inputExtendsOutputSchema.guard(val)) {
expectTypeOf(val).toEqualTypeOf<{ a: string; b: string }>();
} else {
expectTypeOf(val).toEqualTypeOf<unknown>();
}
});

test("to be unavailable when Output *does not* extend Input", () => {
const inputDiffersFromOutputSchema = z
.string()
.transform((arg) => parseFloat(arg));
const val = null as unknown;
// @ts-expect-error - compile error as Input does not extend Output
inputDiffersFromOutputSchema.guard(val);
});
});
7 changes: 7 additions & 0 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -517,6 +517,13 @@ export abstract class ZodType<
isNullable(): boolean {
return this.safeParse(null).success;
}

guard<T extends Output>(
this: ZodType<T, any, T>,
data: unknown
): data is Output {
return this.safeParse(data).success;
}
}

/////////////////////////////////////////
Expand Down

0 comments on commit 47f04a9

Please sign in to comment.