Home > OS >  I want to put nested type names in the first argument of setValue in react-hook-form
I want to put nested type names in the first argument of setValue in react-hook-form

Time:09-06

I want to do
I want to avoid typescript error when "profile.firstName" is passed as the second argument to the function onChange.

Error Description
Arguments of type '"profile.firstName"' cannot be assigned to parameters of type 'keyof User'. ts(2345)

Passing "id", "groupName", and "description" as the second argument to onChange does not cause an error.
However, if "profile.firstName" is passed, an error occurs.


import { useForm } from 'react-hook-form';

import type { CustomNextPage } from 'next';

import { Button, Input } from 'components/Forms';
import { Box } from 'components/Layouts';

export interface User {
  id?: string;
  groupName?: string;
  description?: string;
  profile?: {
    firstName?: string;
    lastName?: string;
    email?: string;
  };
}

const Filter: CustomNextPage = () => {
  const { handleSubmit, setValue, watch } = useForm<User>();
  type P = keyof User;

  const onChange = (value: string, key: P) => {
    setValue(key, value);
  };

  return (
    <>
      <Box>
        <Input onChange={(e) => onChange(e.target.value, 'id')}>ID</Input>
        <Input onChange={(e) => onChange(e.target.value, 'groupName')}>GroupName</Input>
        <Input onChange={(e) => onChange(e.target.value, 'description')}>Description</Input>
        <Input onChange={(e) => onChange(e.target.value, 'profile.firstName')}>FirstName</Input>
        <Box>
          <form>
            <Button type="submit"></Button>
          </form>
        </Box>
      </Box>
    </>
  );
};

export default Filter;


        <Input
          onChange={(e) =>
            onChange(
              {
                ...watch().profile,
                firstName: e.target.value,
              },
              'profile',
            )
          }
        >
          FirstName
        </Input>

Arguments of type '{ firstName: string; lastName?: string | undefined; email?: string | undefined; }' cannot be assigned to parameters of type 'string'. ts(2345)

        <Input
          onChange={(e) =>
            setValue(
              {
                ...watch(),
                profile: {
                  ...watch().profile,
                  firstName: e.target.value,
                },
              },
              'profile',
            )
          }
        >
          FirstName
        </Input>

The argument of type '{ profile: { firstName: string; lastName?: string | undefined; email?: string | undefined; }; id?: string | undefined; groupName?: string | undefined; description? undefined; description?: string | undefined; }' argument of type '"id" | "groupName" | "description" | "profile" | "profile.firstName" | "profile.lastName" | "profile.email "profile.email"' parameters cannot be assigned to parameters of type '"id" | "groupName" | "description" | "profile.firstName" | "profile.lastName" | "profile.email"'. ts(2345)

CodePudding user response:

User has a profile property, which is an object that has the property firstName. So this approach is not going to work.

You could do something like:

<Input onChange={(e) => onChange({
    ...value.profile,
    firstName: e.target.value,
}, 'profile')}>FirstName</Input>

(I'm assuming useForm also returns a value?)

This is a little funky though. Also, onChange.value is no longer just a string.


I think you're sort of drowning in 'convenience' functions.

Maybe just do:

<Input onChange={(e) => setValue("profile", {
    ...value.profile,
    firstName: e.target.value,
})}>FirstName</Input>

And maybe just split this off to a setProfileFirstName funtion.

  • Related