Skip to content

Commit

Permalink
Update ZodType generics
Browse files Browse the repository at this point in the history
  • Loading branch information
colinhacks committed Apr 18, 2024
1 parent b9d59d2 commit 579ecb2
Show file tree
Hide file tree
Showing 4 changed files with 56 additions and 45 deletions.
1 change: 1 addition & 0 deletions deno/lib/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -617,6 +617,7 @@ There are a growing number of tools that are built atop or support Zod natively!
- [`quicktype`](https://app.quicktype.io/): Convert JSON objects and JSON schemas into Zod schemas.
- [`@sanity-typed/zod`](https://github.com/saiichihashimoto/sanity-typed/tree/main/packages/zod): Generate Zod Schemas from [Sanity Schemas](https://www.sanity.io/docs/schema-types).
- [`java-to-zod`](https://github.com/ivangreene/java-to-zod): Convert POJOs to Zod schemas
- [`Orval`](https://github.com/anymaniax/orval): Generate Zod schemas from OpenAPI schemas

#### Mocking

Expand Down
48 changes: 27 additions & 21 deletions deno/lib/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ export type SafeParseReturnType<Input, Output> =
| SafeParseError<Input>;

export abstract class ZodType<
Output = any,
Output = unknown,
Def extends ZodTypeDef = ZodTypeDef,
Input = Output
Input = unknown
> {
readonly _type!: Output;
readonly _output!: Output;
Expand Down Expand Up @@ -669,7 +669,7 @@ function isValidIP(ip: string, version?: IpVersion) {
return false;
}

export class ZodString extends ZodType<string, ZodStringDef> {
export class ZodString extends ZodType<string, ZodStringDef, string> {
_parse(input: ParseInput): ParseReturnType<string> {
if (this._def.coerce) {
input.data = String(input.data);
Expand Down Expand Up @@ -1261,7 +1261,7 @@ export interface ZodNumberDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodNumber extends ZodType<number, ZodNumberDef> {
export class ZodNumber extends ZodType<number, ZodNumberDef, number> {
_parse(input: ParseInput): ParseReturnType<number> {
if (this._def.coerce) {
input.data = Number(input.data);
Expand Down Expand Up @@ -1546,7 +1546,7 @@ export interface ZodBigIntDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodBigInt extends ZodType<bigint, ZodBigIntDef> {
export class ZodBigInt extends ZodType<bigint, ZodBigIntDef, bigint> {
_parse(input: ParseInput): ParseReturnType<bigint> {
if (this._def.coerce) {
input.data = BigInt(input.data);
Expand Down Expand Up @@ -1747,7 +1747,7 @@ export interface ZodBooleanDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodBoolean extends ZodType<boolean, ZodBooleanDef> {
export class ZodBoolean extends ZodType<boolean, ZodBooleanDef, boolean> {
_parse(input: ParseInput): ParseReturnType<boolean> {
if (this._def.coerce) {
input.data = Boolean(input.data);
Expand Down Expand Up @@ -1793,7 +1793,7 @@ export interface ZodDateDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodDate;
}

export class ZodDate extends ZodType<Date, ZodDateDef> {
export class ZodDate extends ZodType<Date, ZodDateDef, Date> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
if (this._def.coerce) {
input.data = new Date(input.data);
Expand Down Expand Up @@ -1962,7 +1962,11 @@ export interface ZodUndefinedDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodUndefined;
}

export class ZodUndefined extends ZodType<undefined, ZodUndefinedDef> {
export class ZodUndefined extends ZodType<
undefined,
ZodUndefinedDef,
undefined
> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.undefined) {
Expand Down Expand Up @@ -1997,7 +2001,7 @@ export interface ZodNullDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNull;
}

export class ZodNull extends ZodType<null, ZodNullDef> {
export class ZodNull extends ZodType<null, ZodNullDef, null> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.null) {
Expand Down Expand Up @@ -2030,7 +2034,7 @@ export interface ZodAnyDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodAny;
}

export class ZodAny extends ZodType<any, ZodAnyDef> {
export class ZodAny extends ZodType<any, ZodAnyDef, any> {
// to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject.
_any = true as const;
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
Expand All @@ -2055,7 +2059,7 @@ export interface ZodUnknownDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodUnknown;
}

export class ZodUnknown extends ZodType<unknown, ZodUnknownDef> {
export class ZodUnknown extends ZodType<unknown, ZodUnknownDef, unknown> {
// required
_unknown = true as const;
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
Expand All @@ -2081,7 +2085,7 @@ export interface ZodNeverDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNever;
}

export class ZodNever extends ZodType<never, ZodNeverDef> {
export class ZodNever extends ZodType<never, ZodNeverDef, never> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const ctx = this._getOrReturnCtx(input);
addIssueToContext(ctx, {
Expand Down Expand Up @@ -2110,7 +2114,7 @@ export interface ZodVoidDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodVoid;
}

export class ZodVoid extends ZodType<void, ZodVoidDef> {
export class ZodVoid extends ZodType<void, ZodVoidDef, void> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.undefined) {
Expand Down Expand Up @@ -3374,7 +3378,7 @@ export class ZodIntersection<
export type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]];
export type AssertArray<T> = T extends any[] ? T : never;
export type OutputTypeOfTuple<T extends ZodTupleItems | []> = AssertArray<{
[k in keyof T]: T[k] extends ZodType<any, any> ? T[k]["_output"] : never;
[k in keyof T]: T[k] extends ZodType<any, any, any> ? T[k]["_output"] : never;
}>;
export type OutputTypeOfTupleWithRest<
T extends ZodTupleItems | [],
Expand All @@ -3384,7 +3388,7 @@ export type OutputTypeOfTupleWithRest<
: OutputTypeOfTuple<T>;

export type InputTypeOfTuple<T extends ZodTupleItems | []> = AssertArray<{
[k in keyof T]: T[k] extends ZodType<any, any> ? T[k]["_input"] : never;
[k in keyof T]: T[k] extends ZodType<any, any, any> ? T[k]["_input"] : never;
}>;
export type InputTypeOfTupleWithRest<
T extends ZodTupleItems | [],
Expand Down Expand Up @@ -3982,7 +3986,7 @@ export class ZodFunction<
});
}

returns<NewReturnType extends ZodType<any, any>>(
returns<NewReturnType extends ZodType<any, any, any>>(
returnType: NewReturnType
): ZodFunction<Args, NewReturnType> {
return new ZodFunction({
Expand Down Expand Up @@ -4089,7 +4093,7 @@ export interface ZodLiteralDef<T = any> extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodLiteral;
}

export class ZodLiteral<T> extends ZodType<T, ZodLiteralDef<T>> {
export class ZodLiteral<T> extends ZodType<T, ZodLiteralDef<T>, T> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
if (input.data !== this._def.value) {
const ctx = this._getOrReturnCtx(input);
Expand Down Expand Up @@ -4174,7 +4178,8 @@ function createZodEnum(

export class ZodEnum<T extends [string, ...string[]]> extends ZodType<
T[number],
ZodEnumDef<T>
ZodEnumDef<T>,
T[number]
> {
#cache: Set<T[number]> | undefined;

Expand Down Expand Up @@ -4284,7 +4289,8 @@ export type EnumLike = { [k: string]: string | number; [nu: number]: string };

export class ZodNativeEnum<T extends EnumLike> extends ZodType<
T[keyof T],
ZodNativeEnumDef<T>
ZodNativeEnumDef<T>,
T[keyof T]
> {
#cache: Set<T[keyof T]> | undefined;
_parse(input: ParseInput): ParseReturnType<T[keyof T]> {
Expand Down Expand Up @@ -4851,7 +4857,7 @@ export interface ZodNaNDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNaN;
}

export class ZodNaN extends ZodType<number, ZodNaNDef> {
export class ZodNaN extends ZodType<number, ZodNaNDef, number> {
_parse(input: ParseInput): ParseReturnType<any> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.nan) {
Expand Down Expand Up @@ -5073,7 +5079,7 @@ export function custom<T>(
*
*/
fatal?: boolean
): ZodType<T> {
): ZodType<T, ZodTypeDef, unknown> {
if (check)
return ZodAny.create().superRefine((data, ctx) => {
if (!check(data)) {
Expand Down
4 changes: 1 addition & 3 deletions playground.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,4 @@ import { z } from "./src";

z;

const dateRegexSource = `((\\d\\d[2468][048]|\\d\\d[13579][26]|\\d\\d0[48]|[02468][048]00|[13579][26]00)-02-29|\\d{4}-((0[13578]|1[02])-(0[1-9]|[12]\\d|3[01])|(0[469]|11)-(0[1-9]|[12]\\d|30)|(02)-(0[1-9]|1\\d|2[0-8])))`;
const dateRegex = new RegExp(`^${dateRegexSource}$`);
console.log(dateRegex.test("2400-02-29"));
console.log(z.string().ip().parse("255.255.255.255"));
48 changes: 27 additions & 21 deletions src/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ export type SafeParseReturnType<Input, Output> =
| SafeParseError<Input>;

export abstract class ZodType<
Output = any,
Output = unknown,
Def extends ZodTypeDef = ZodTypeDef,
Input = Output
Input = unknown
> {
readonly _type!: Output;
readonly _output!: Output;
Expand Down Expand Up @@ -669,7 +669,7 @@ function isValidIP(ip: string, version?: IpVersion) {
return false;
}

export class ZodString extends ZodType<string, ZodStringDef> {
export class ZodString extends ZodType<string, ZodStringDef, string> {
_parse(input: ParseInput): ParseReturnType<string> {
if (this._def.coerce) {
input.data = String(input.data);
Expand Down Expand Up @@ -1261,7 +1261,7 @@ export interface ZodNumberDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodNumber extends ZodType<number, ZodNumberDef> {
export class ZodNumber extends ZodType<number, ZodNumberDef, number> {
_parse(input: ParseInput): ParseReturnType<number> {
if (this._def.coerce) {
input.data = Number(input.data);
Expand Down Expand Up @@ -1546,7 +1546,7 @@ export interface ZodBigIntDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodBigInt extends ZodType<bigint, ZodBigIntDef> {
export class ZodBigInt extends ZodType<bigint, ZodBigIntDef, bigint> {
_parse(input: ParseInput): ParseReturnType<bigint> {
if (this._def.coerce) {
input.data = BigInt(input.data);
Expand Down Expand Up @@ -1747,7 +1747,7 @@ export interface ZodBooleanDef extends ZodTypeDef {
coerce: boolean;
}

export class ZodBoolean extends ZodType<boolean, ZodBooleanDef> {
export class ZodBoolean extends ZodType<boolean, ZodBooleanDef, boolean> {
_parse(input: ParseInput): ParseReturnType<boolean> {
if (this._def.coerce) {
input.data = Boolean(input.data);
Expand Down Expand Up @@ -1793,7 +1793,7 @@ export interface ZodDateDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodDate;
}

export class ZodDate extends ZodType<Date, ZodDateDef> {
export class ZodDate extends ZodType<Date, ZodDateDef, Date> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
if (this._def.coerce) {
input.data = new Date(input.data);
Expand Down Expand Up @@ -1962,7 +1962,11 @@ export interface ZodUndefinedDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodUndefined;
}

export class ZodUndefined extends ZodType<undefined, ZodUndefinedDef> {
export class ZodUndefined extends ZodType<
undefined,
ZodUndefinedDef,
undefined
> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.undefined) {
Expand Down Expand Up @@ -1997,7 +2001,7 @@ export interface ZodNullDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNull;
}

export class ZodNull extends ZodType<null, ZodNullDef> {
export class ZodNull extends ZodType<null, ZodNullDef, null> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.null) {
Expand Down Expand Up @@ -2030,7 +2034,7 @@ export interface ZodAnyDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodAny;
}

export class ZodAny extends ZodType<any, ZodAnyDef> {
export class ZodAny extends ZodType<any, ZodAnyDef, any> {
// to prevent instances of other classes from extending ZodAny. this causes issues with catchall in ZodObject.
_any = true as const;
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
Expand All @@ -2055,7 +2059,7 @@ export interface ZodUnknownDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodUnknown;
}

export class ZodUnknown extends ZodType<unknown, ZodUnknownDef> {
export class ZodUnknown extends ZodType<unknown, ZodUnknownDef, unknown> {
// required
_unknown = true as const;
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
Expand All @@ -2081,7 +2085,7 @@ export interface ZodNeverDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNever;
}

export class ZodNever extends ZodType<never, ZodNeverDef> {
export class ZodNever extends ZodType<never, ZodNeverDef, never> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const ctx = this._getOrReturnCtx(input);
addIssueToContext(ctx, {
Expand Down Expand Up @@ -2110,7 +2114,7 @@ export interface ZodVoidDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodVoid;
}

export class ZodVoid extends ZodType<void, ZodVoidDef> {
export class ZodVoid extends ZodType<void, ZodVoidDef, void> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.undefined) {
Expand Down Expand Up @@ -3374,7 +3378,7 @@ export class ZodIntersection<
export type ZodTupleItems = [ZodTypeAny, ...ZodTypeAny[]];
export type AssertArray<T> = T extends any[] ? T : never;
export type OutputTypeOfTuple<T extends ZodTupleItems | []> = AssertArray<{
[k in keyof T]: T[k] extends ZodType<any, any> ? T[k]["_output"] : never;
[k in keyof T]: T[k] extends ZodType<any, any, any> ? T[k]["_output"] : never;
}>;
export type OutputTypeOfTupleWithRest<
T extends ZodTupleItems | [],
Expand All @@ -3384,7 +3388,7 @@ export type OutputTypeOfTupleWithRest<
: OutputTypeOfTuple<T>;

export type InputTypeOfTuple<T extends ZodTupleItems | []> = AssertArray<{
[k in keyof T]: T[k] extends ZodType<any, any> ? T[k]["_input"] : never;
[k in keyof T]: T[k] extends ZodType<any, any, any> ? T[k]["_input"] : never;
}>;
export type InputTypeOfTupleWithRest<
T extends ZodTupleItems | [],
Expand Down Expand Up @@ -3982,7 +3986,7 @@ export class ZodFunction<
});
}

returns<NewReturnType extends ZodType<any, any>>(
returns<NewReturnType extends ZodType<any, any, any>>(
returnType: NewReturnType
): ZodFunction<Args, NewReturnType> {
return new ZodFunction({
Expand Down Expand Up @@ -4089,7 +4093,7 @@ export interface ZodLiteralDef<T = any> extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodLiteral;
}

export class ZodLiteral<T> extends ZodType<T, ZodLiteralDef<T>> {
export class ZodLiteral<T> extends ZodType<T, ZodLiteralDef<T>, T> {
_parse(input: ParseInput): ParseReturnType<this["_output"]> {
if (input.data !== this._def.value) {
const ctx = this._getOrReturnCtx(input);
Expand Down Expand Up @@ -4174,7 +4178,8 @@ function createZodEnum(

export class ZodEnum<T extends [string, ...string[]]> extends ZodType<
T[number],
ZodEnumDef<T>
ZodEnumDef<T>,
T[number]
> {
#cache: Set<T[number]> | undefined;

Expand Down Expand Up @@ -4284,7 +4289,8 @@ export type EnumLike = { [k: string]: string | number; [nu: number]: string };

export class ZodNativeEnum<T extends EnumLike> extends ZodType<
T[keyof T],
ZodNativeEnumDef<T>
ZodNativeEnumDef<T>,
T[keyof T]
> {
#cache: Set<T[keyof T]> | undefined;
_parse(input: ParseInput): ParseReturnType<T[keyof T]> {
Expand Down Expand Up @@ -4851,7 +4857,7 @@ export interface ZodNaNDef extends ZodTypeDef {
typeName: ZodFirstPartyTypeKind.ZodNaN;
}

export class ZodNaN extends ZodType<number, ZodNaNDef> {
export class ZodNaN extends ZodType<number, ZodNaNDef, number> {
_parse(input: ParseInput): ParseReturnType<any> {
const parsedType = this._getType(input);
if (parsedType !== ZodParsedType.nan) {
Expand Down Expand Up @@ -5073,7 +5079,7 @@ export function custom<T>(
*
*/
fatal?: boolean
): ZodType<T> {
): ZodType<T, ZodTypeDef, unknown> {
if (check)
return ZodAny.create().superRefine((data, ctx) => {
if (!check(data)) {
Expand Down

0 comments on commit 579ecb2

Please sign in to comment.