Skip to content

Commit

Permalink
Merge pull request #135 from watershed-climate/main
Browse files Browse the repository at this point in the history
fix unwrap for default, arrays of enums, and generally all unwrappables in every order we support
  • Loading branch information
scamden authored Sep 8, 2023
2 parents e6d94a6 + eba187e commit 205892d
Show file tree
Hide file tree
Showing 2 changed files with 95 additions and 21 deletions.
72 changes: 72 additions & 0 deletions src/__tests__/unwrap.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -60,4 +60,76 @@ describe("unwrap types", () => {
}}
/>;
});
it("should have the correct types for .default()", () => {
function TextField(_: { one: string }) {
return <div />;
}
const mapping = [[z.string(), TextField]] as const;

const Form = createTsForm(mapping);

<Form
onSubmit={(data) => {
data.optionalNullableString;
}}
schema={z.object({
optionalNullableString: z
.string()
.default("moo")
.describe("something")
.optional()
.nullable(),
})}
props={{
optionalNullableString: {
one: "One",
},
}}
/>;
});
it("should have the correct types for .enum().array()", () => {
function TextField(_: { one: string }) {
return <div />;
}
const mapping = [
[z.enum(["placeholder"]).array(), TextField],
[z.enum(["placeholder"]), TextField],
] as const;

const Form = createTsForm(mapping);

<Form
onSubmit={(data) => {
data.enumArray;
data.enum;
}}
schema={z.object({
// tests we can match despite having different enum than the mapping
enum: z.enum(["moo"]),
// tests we can match arrays of enums
enumArray: z.enum(["moo"]).array(),
// tests we can match the deepest possible combination of unwrappable things
enumArrayWithEverything: z
.enum(["moo"])
.optional()
.nullable()
.default("moo")
.array()
.optional()
.nullable()
.default(["moo"]),
})}
props={{
enumArrayWithEverything: {
one: "One",
},
enumArray: {
one: "One",
},
enum: {
one: "One",
},
}}
/>;
});
});
44 changes: 23 additions & 21 deletions src/unwrap.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import {
z,
ZodArray,
ZodDefault,
ZodEnum,
ZodFirstPartyTypeKind,
ZodNullable,
Expand Down Expand Up @@ -73,26 +74,27 @@ export function unwrapEffects(effects: RTFSupportedZodTypes) {
return effects;
}

export type UnwrapPreviousLevel = [never, 0, 1, 2, 3];
export type UnwrapMaxRecursionDepth = 3;

/**
* I'd like this to be recursive but it creates an "infinite instantiation error" if I make it call itself.
* This is probably just as good for normal usage?
* At most we can see for a given type z.enum().optional().nullable().default("foo")
* so we limit recursion depth to 3
* then we can see the same again for the inner type of an array
* z.enum(["moo"]).optional().nullable().default('moo').array().optional().nullable().default(['moo'])
* so we restart the counter for array only, leaving us with a max of 6
* and ts seems ok with this because the type is very simple
*/
export type UnwrapZodType<T extends RTFSupportedZodTypes> =
T extends ZodOptional<any>
? T["_def"]["innerType"] extends ZodNullable<any>
? GenericizeLeafTypes<T["_def"]["innerType"]["_def"]["innerType"]>
: GenericizeLeafTypes<T["_def"]["innerType"]>
: T extends ZodNullable<any>
? T["_def"]["innerType"] extends ZodOptional<any>
? GenericizeLeafTypes<T["_def"]["innerType"]["_def"]["innerType"]>
: GenericizeLeafTypes<T["_def"]["innerType"]>
: GenericizeLeafTypes<T>;

export type GenericizeLeafTypes<T extends RTFSupportedZodTypes> =
ArrayAsLengthAgnostic<EnumAsAnyEnum<T>>;

export type ArrayAsLengthAgnostic<T extends RTFSupportedZodTypes> =
T extends ZodArray<any, any> ? ZodArray<T["element"]> : T;

export type EnumAsAnyEnum<T extends RTFSupportedZodTypes> =
T extends ZodEnum<any> ? ZodEnum<any> : T;
export type UnwrapZodType<
T extends RTFSupportedZodTypes,
Level extends UnwrapPreviousLevel[number] = UnwrapMaxRecursionDepth
> = [Level] extends [never]
? never
: T extends ZodOptional<any> | ZodNullable<any> | ZodDefault<any>
? UnwrapZodType<T["_def"]["innerType"], UnwrapPreviousLevel[Level]>
: T extends ZodArray<any, any>
? // allow another 3 levels of recursion for the array
ZodArray<UnwrapZodType<T["element"], UnwrapMaxRecursionDepth>>
: T extends ZodEnum<any>
? ZodEnum<any>
: T;

1 comment on commit 205892d

@vercel
Copy link

@vercel vercel bot commented on 205892d Sep 8, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please sign in to comment.