Skip to content

Commit

Permalink
make prop type ignore array cardinality
Browse files Browse the repository at this point in the history
  • Loading branch information
scamden committed Apr 4, 2023
1 parent dbf9064 commit 9a95796
Show file tree
Hide file tree
Showing 2 changed files with 98 additions and 4 deletions.
87 changes: 87 additions & 0 deletions src/__tests__/createSchemaForm.test.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -1593,4 +1593,91 @@ describe("createSchemaForm", () => {
numberArray: [1, 2, 3],
});
});
it("should render an array component with objects, and should map nonempty()", async () => {
const mockOnSubmit = jest.fn(() => {});
const objectSchema = z.object({
text: z.string(),
numberField: z.number(),
});
function DynamicArray(_props: { something?: boolean }) {
const {
field: { value, onChange },
} = useTsController<z.infer<typeof objectSchema>[]>();

return (
<div data-testid="dynamic-array">
<button
type="button"
data-testid="add-element"
onClick={() => {
onChange(value?.concat([{ text: "", numberField: 2 }]));
}}
>
Add one element to array
</button>
{value?.map((val, i) => {
return (
<input
key={i}
data-testid={`dynamic-array-input${i}`}
value={val.text}
onChange={(e) =>
onChange(
value?.map((v, j) =>
i === j ? { ...v, text: e.target.value } : v
)
)
}
/>
);
})}
</div>
);
}

function NumberField() {
return <div>number</div>;
}

const mapping = [
[objectSchema.array(), DynamicArray],
[z.number(), NumberField],
] as const;

const Form = createTsForm(mapping);

const schema = z.object({
arrayField: objectSchema.array().nonempty(),
numberArray: z.number().array(),
});
const defaultValues = {
arrayField: [
{ text: "name", numberField: 2 },
{ text: "name2", numberField: 2 },
],
numberArray: [1, 2, 3],
};
render(
<Form
onSubmit={mockOnSubmit}
schema={schema}
defaultValues={defaultValues}
props={{ arrayField: { something: true } }}
renderAfter={() => {
return <button type="submit">submit</button>;
}}
></Form>
);

const numberNodes = screen.queryAllByText("number");
numberNodes.forEach((node) => expect(node).toBeInTheDocument());
expect(numberNodes).toHaveLength(3);

expect(screen.getByTestId("dynamic-array")).toBeInTheDocument();
const addElementButton = screen.getByTestId("add-element");
await userEvent.click(addElementButton);

const inputs = screen.getAllByTestId(/dynamic-array-input/);
expect(inputs.length).toBe(3);
});
});
15 changes: 11 additions & 4 deletions src/unwrap.tsx
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import {
z,
ZodArray,
ZodEnum,
ZodFirstPartyTypeKind,
ZodNullable,
Expand Down Expand Up @@ -78,12 +79,18 @@ export function unwrapEffects(effects: RTFSupportedZodTypes) {
*/
export type UnwrapZodType<T extends RTFSupportedZodTypes> =
T extends ZodOptional<any>
? EnumAsAnyEnum<T["_def"]["innerType"]>
? GenericizeLeafTypes<T["_def"]["innerType"]>
: T extends ZodNullable<any>
? T["_def"]["innerType"] extends ZodOptional<any>
? EnumAsAnyEnum<T["_def"]["innerType"]["_def"]["innerType"]>
: EnumAsAnyEnum<T["_def"]["innerType"]>
: EnumAsAnyEnum<T>;
? 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;

0 comments on commit 9a95796

Please sign in to comment.