react-hook-form / resolvers

📋 Validation resolvers: Yup, Zod, Superstruct, Joi, Vest, Class Validator, io-ts, Nope, computed-types, typanion, Ajv, TypeBox, ArkType, Valibot, effect-ts and VineJS
https://react-hook-form.com/
MIT License
1.67k stars 151 forks source link

Extend typeboxResolver with additional types; getting "Unknown type" in Visit3 #664

Open mnpenner opened 4 months ago

mnpenner commented 4 months ago

Is your feature request related to a problem? Please describe.

Yes. I'm trying to use typeboxResolver with ElysiaJS to share a schema between client and server. This almost works, except Elysia defines extra types like Files which I want to use. Specifically, Elysia defines it as _sinclair_typebox.TTransform<_sinclair_typebox.TUnsafe<File[]>, File[]>.

Describe the solution you'd like

Somewhere in @hookform/resolvers there's this big switch case:

function* Visit3(schema, references, path, value) {
  const references_ = IsDefined(schema.$id) ? [...references, schema] : references;
  const schema_ = schema;
  switch (schema_[Kind]) {
    case "Any":
      return yield* FromAny(schema_, references_, path, value);
    case "Array":
      return yield* FromArray3(schema_, references_, path, value);
    // ...
    default:
      if (!type_exports.Has(schema_[Kind]))
        throw new ValueErrorsUnknownTypeError(schema);
      return yield* FromKind(schema_, references_, path, value);
  }
}

I'm hitting the end there. Please provide an injection point somewhere in there so I can add support for "Files" manually.

Describe alternatives you've considered

I'm really not sure how else I can solve this. I can mangle the type as Any I guess but that'd be rather unfortunate.

Additional context

Here's the code I'm trying:

import {t, type Static} from "elysia"

export const UploadBody = t.Object({
    account: t.Number(),
    files: t.Files(),
})

export type UploadBodyType = Static<typeof UploadBody>

export function UploadForm() {
    const balancesQuery = useSuspenseQuery(balanceOptions)

    const {
        register,
        handleSubmit,
        setValue,
        getValues,
        formState: { errors, isSubmitting },
    } = useForm<UploadBodyType>({
        resolver: typeboxResolver(UploadBody),
    });

    const onSubmit: SubmitHandler<UploadBodyType> = data => {
        console.log(data)
    }
    return (
        <form onSubmit={handleSubmit(onSubmit)}>
            <div>
                <input type="file"
                    ref={fileInput}
                    multiple
                    onChange={ev => setValue('files', ev.currentTarget.files ? Array.from(ev.currentTarget.files) : [])} />
                {errors.files?.message}
            </div>
            <div>
                <button type="submit" disabled={isSubmitting}>Upload</button>
            </div>
        </form>
    )
}

Where t is mostly just a re-export of sinclair/typebox's Type with a few extensions.