添加链接
link管理
链接快照平台
  • 输入网页链接,自动生成快照
  • 标签化管理网页链接
相关文章推荐
霸气的铅笔  ·  CRUD with C#/SQL in ...·  3 天前    · 
痴情的机器猫  ·  C# .NET CORE .NET6 ...·  昨天    · 
爱跑步的电池  ·  API Documentation·  昨天    · 
爱健身的稀饭  ·  数据库内核月报·  4 月前    · 
逼格高的花生  ·  ModuleNotFoundError: ...·  5 月前    · 
才高八斗的豆浆  ·  How make a if ...·  6 月前    · 
逃跑的剪刀  ·  Android ...·  7 月前    · 

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement . We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

This seems like a duplicate of #2984 .

Describe the bug

I am experiencing this issue after following the Control example in your documentation and using any 7.x release. (have tried 7.0, 7.1, 7.2, 7.3 and patch versions of all)

I am calling useForm with a generic type in the shape of my form values -- the error occurs whether I use a generic or not -- and pass control to my components which wrap form values. My components accept a property control: Control per your example.

I get the error error TS2322: Type 'Control<FormValues>' is not assignable to type 'Control<FieldValues>'. Types of property 'register' are incompatible. and if I don't assign a generic it will just read the object type e.g. Control<{ valuea: string, valueb: boolean }> .

To Reproduce
Steps to reproduce the behavior:

  • Assign a set of form values to the generic input of useForm
  • Pass control to component which accepts Control type from react-hook-form
  • Witness issue
  • Codesandbox link (Required)
    https://codesandbox.io/s/nervous-rubin-pdh9g?file=/src/App.tsx

    Expected behavior

    I expect the generic type that I supply to useForm to be respected throughout the rest of the form interfaces as specified in the documentation.

    Screenshots

    Desktop (please complete the following information):

  • OS: MacOS
  • Browser: All browsers -- fails basic TSC compilation
  • Version: 7.x
  • I have a very similar issue. However, I think your TS definition is "wrong" (same as mine). You define control props as Control in ICheckboxProps but you pass there Control<MyFormValues> . I am struggling to find a way of how to use useForm<FormInputsType> with generic form components. I have found few solutions, so far:

  • type control prop as unknown as Control<FieldValues>
  • use JSX type generics https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-9.html#generic-type-arguments-in-jsx-elements
  • do not pass type generic to useForm
  • I hope there is a way to declare a shared form field component and use it with type-specific form? Can type generic be ignored on Control maybe?

    Edit: fixed first example

    Now I also see that the doc is different from codesandbox! https://react-hook-form.com/ts#Control vs. https://codesandbox.io/s/control-2mg07

    function IsolateReRender({ control }: { control: Control }) { vs . function IsolateReRender({ control }: { control: Control<FormValues> }) {

    @jordan-jarolim thank you for your response! I've had no success with the options you mentioned. It looks like I might have to go with Option 2 despite my apprehension.

    Option 1 (type control prop as unknown as Control<MyFormValues> ) fails with:

    error TS2365: Operator '>' cannot be applied to types 'Control<FieldValues>' and '{ defaultValues: { checked: boolean; }; mode: string; }'.
    error TS2693: 'FormValues' only refers to a type, but is being used as a value here.
    

    I have been avoiding Option 2 you mentioned because I feel like the syntax is confusing with JSX -- if at all possible I would like to avoid this.

    Option 3 fails as mentioned in my original post:

    if I don't assign a generic it will just read the object type e.g. Control<{ valuea: string, valueb: boolean }>.

  • useForm<MyType> in combination with control={(yourControlInstance as unknown) as Control<FieldValues>} works for me, its still just a workaround tho.
  • I agree!
  • I am not sure if we have the same issue here... if you don't pass generic to useForm it takes FieldValues as default and this is the same for Control type. You can try to define you interface as control: Control<FieldValues>
  • I hope we will get some support on this :)

    Jordan, I was able to get item 1 working. While it is kludgy it will be acceptable for now.

    I was unsuccessful not passing a generic to useForm even with Control<FieldValues> typing (not just Control sans generic).

    Regarding item 2 (Generics in JSX) I think it would be useful for a more accurately representative example in codesandbox e.g. not containing both components in the same file. My particular implementation is being built for reuse, and so the customized FieldValues per form will not be able to simply be imported and used by the fields themselves.

    Hello !
    I'm not quite sure I understand the problem entirely but if the goal is to have a generic component over the type of the useForm data structure, I think something like this should do the trick:

    export interface IReactHookFormFieldProps<T> {
      name: FieldPath<T>;
      control: Control<T>;
      rules?: RegisterOptions<T>;
    

    Here is a sandbox showing it with your code.

    For fun I've made another one that ensure that the key passed to the component is a boolean

    You can find this version here (If you're interested)

    Hope it can be helpful ! :)

    twobit, DoctorJohn, alimtunc, TimPetricola, and kevinmamaqi reacted with thumbs up emoji johndatserakis reacted with heart emoji All reactions

    You define an interface to expect T as generic but then you don't pass it from the component

    In this case TS will be able to infer the type of T based off the props. The only use-case I know about for using
    <Component<MyType> {...props} /> is when you when to opt out of TS compiler type inference which here isn't the case.

    Here is a great reference about that

    it's basically turning off TS check for Control ?

    I don't really get what you mean by "turning off TS check".
    With the defined interface, TS expect a prop control: Control<T>, T being a type that extends Record<string, any> which is the same constraint as the Control itself.

    Why this issue is closed? It still throws an error.

    My LoginFormValues type is

    export type LoginFormValues = {
      username: string;
      password: string;
    

    My useForm is

    const {
      control,
      handleSubmit,
      formState,
    } = useForm<LoginFormValues>({
      defaultValues: {
        username: '',
        password: '',
    

    And my custom input is

    export type InputFieldProps = {
      control: Control<FieldValues, any>;
    

    So, when i pass control to the InputField it throws an error above

    <InputField
      name="username"
      size="large"
      theme="primary"
      color="light"
      namespace="login_form"
      control={control} // this is marked red
    
    Type 'Control<LoginFormValues, any>' is not assignable to type 'Control<FieldValues, any>'.
      The types of '_options.resolver' are incompatible between these types.
        Type 'Resolver<LoginFormValues, any>' is not assignable to type 'Resolver<FieldValues, any>'.
    

    This is really frustrating.

    @artuska, I'm getting the same error. I think it might have something to do specifically with the use of a resolver as a parameter to useForm that isn't handled by other generic examples.
    My error:

    Type 'Control<{ email: string; family_name: string; given_name: string; groups: string[]; username: string; }, any>' is not assignable to type 'Control<FieldValues, any>'.
      The types of '_options.resolver' are incompatible between these types.
        Type 'Resolver<{ email: string; family_name: string; given_name: string; groups: string[]; username: string; }, any> | undefined' is not assignable to type 'Resolver<FieldValues, any> | undefined'.
          Type 'Resolver<{ email: string; family_name: string; given_name: string; groups: string[]; username: string; }, any>' is not assignable to type 'Resolver<FieldValues, any>'.
    

    Here is my code. Interestingly enough there isn't an error with the controller component that for family_name but there is for groups. I wonder if it has to do with the types differences: string vs string[]?

    // form.ts
    const baseUserSchema = z.object({
      email: z.string().email(),
      family_name: z.string().min(1, { message: "Family Name is required" }),
      given_name: z.string().min(1, { message: "Given Name is required" }),
      groups: z.array(z.string()).min(1, { message: "Group is required" }),
      username: z.string().min(1, { message: "Username is required" }),
    });
    type Schema = z.infer<typeof baseUserSchema>;
    const { control, handleSubmit, reset, setValue } = useForm<Schema>({
        resolver: zodResolver(baseUserSchema),
        defaultValues: new CreateCognitoUser(),
      });
    <SmartTextField
              control={control} // no error
              data-test="family_name"
              label="Family Name"
              loading={loadingUser}
              name="family_name"
    <SmartMultiSelectField
              control={control} // error
              data-test="groups"
              label="Groups"
              loading={loadingGroups}
              name="groups"
              options={groupNameOptions}
    
    // SmartMultiSelectField.tsx
    import { ReactElement } from "react";
    import { Placeholder } from "@aws-amplify/ui-react";
    import { useController, UseControllerProps } from "react-hook-form";
    import type { FieldValues } from "react-hook-form";
    import { BaseSmartInputProps } from "./baseProps.js";
    import { Box, MultiSelectField, MultiSelectFieldProps } from "../index.js";
    export interface SmartMultiSelectFieldProps<T>
      extends Omit<BaseSmartInputProps<T>, "control" | "name">,
        Omit<MultiSelectFieldProps, "name">,
        UseControllerProps<T> {}
    export function SmartMultiSelectField<T extends FieldValues>(
      props: SmartMultiSelectFieldProps<T>
    ): ReactElement {
      const {
        control,
        errorMessage,
        hasError,
        label,
        loading,
        name,
        ...multiSelectFieldProps
      } = props;
      const {
        field: { ref, onChange, value },
        fieldState: { error, invalid },
      } = useController({ name, control });
      return loading ? (
        <Box css={{ display: "flex", flexDirection: "column", gap: "$2" }}>
          <label className="amplify-label">{label}</label>
          <Placeholder height={40} />
        </Box>
      ) : (
        <MultiSelectField
          {...(multiSelectFieldProps as Omit<
            MultiSelectFieldProps,
            "label" | "name"
          ref={ref}
          errorMessage={errorMessage || error?.message}
          hasError={hasError || invalid}
          name={name}
          label={label}
          onChange={onChange}
          value={value}
    
    // baseProps.js
    import { ReactNode } from "react";
    import { Control, FieldValues, FieldPath } from "react-hook-form";
    export interface BaseSmartInputProps<T extends FieldValues> {
      loading?: boolean;
      label: ReactNode;
      name: FieldPath<T>;
      control: Control<T>;
              

    Hi @bluebill1049 and @bestickley

    CSB -> https://codesandbox.io/s/react-hook-form-mui-5-v7-controller-ts-10d64d?file=/src/form/InputField.tsx

    I'm also struggling with this error and I ended up using control: any; 😁

    Could you take a look how to pass generics in this case ?

    Props for MUI components:

    type Props = Omit<TextFieldProps, "name"> & {
      control: Control<any, object>;
      disableErrorSpace?: boolean;
      name: string;
      maxLength?: number;
    const InputField = ({
      control,
      disableErrorSpace,
      name,
      required,
      label,
      maxLength = 50,
      ...restProps
    }: Props) => (
      <Controller
        render={({ field: { ref, ...restField }, fieldState: { error } }) => (

    I saw some issues regarding this topic, but it might be the best place to address the issue.
    #8808
    #8618

    Cheers,

    This is how how I typed it:

    https://codesandbox.io/s/react-hook-form-mui-5-v7-controller-ts-10d64d?file=/src/form/InputField.tsx

    import { Control, Controller, FieldValues, Path } from "react-hook-form";
    import { TextField, TextFieldProps } from "@mui/material";
    import { textFieldValidator } from "./validators";
    type Props<T extends FieldValues> = Omit<TextFieldProps, "name"> & {
      control: Control<T, object>;
      disableErrorSpace?: boolean;
      name: Path<T>;
      maxLength?: number;
    const InputField = <T extends FieldValues>({
      control,
      disableErrorSpace,
      name,
      required,
      label,
      maxLength = 50,
      ...restProps
    }: Props<T>) => (
      <Controller
        render={({ field: { ref, ...restField }, fieldState: { error } }) => (
          <TextField
          [...]