react-hook-form通用字段组件

问题描述 投票:0回答:1

我正在尝试实现可在根表单级别和嵌套字段中使用的表单字段组件。

export type FirstNameField = {
  firstName: string;
};

type GenericFormType<T, NS extends string | never = never> = NS extends never ? T : Record<NS, T>;

export type FirstNameProps<T extends string | never = never> = {
  namespace?: T;
};

export const FirstName = <T extends string | never = never>({ namespace }: FirstNameProps<T>) => {
  const form = useFormContext<GenericFormType<FirstNameField, T>>();
  return (
    <FormInput<GenericFormType<FirstNameField, T>>
      {...form}
      fieldName={namespace ? `${namespace}.firstName` : 'firstName'}
      label="First name"
      validation={{
        required: 'Required',
      }}
    />
  );
};

interface Props<T extends FieldValues = FieldValues> extends UseFormReturn<T> {
  label?: ReactNode;
  fieldName: FieldPath<T>;
  validation?: RegisterOptions;
}

export function FormInput<T extends FieldValues = FieldValues>(props: Props<T>) {
  return null;
}

所以有错误 在行

fieldName={namespace ? `${namespace}.firstName` : 'firstName'}

说的是

TS2322: Type 'firstName' | `${T}.firstName` is not assignable to type Path<GenericFormType<FirstNameField, T>>
Type string is not assignable to type Path<GenericFormType<FirstNameField, T>>

所以我尝试使用泛型类型和其他类型,但没有成功

reactjs typescript typescript-generics react-hook-form react-typescript
1个回答
0
投票

当我努力解决这个问题时,我通过将名称设置为与 T 类似的类型来解决它,但扩展了路径(路径来自react-hook-form)。在你的例子中就是这样。

interface Props<T extends FieldValues = FieldValues, TName extends Path<TFieldValues> = Path<TFieldValues>,> extends UseFormReturn<T> {
  label?: ReactNode;
  fieldName: TName;
  validation?: RegisterOptions;
}

然后

export function FormInput<T extends FieldValues = FieldValues,TName extends Path<TFieldValues> = Path<TFieldValues>>(props: Props<T, TName>) {
  return null;
}

我的自定义表单组件如下所示,它将其他输入组件(输入、文本区域、复选框、选择)作为子组件:

interface FormComponentProps<
  TFieldValues extends FieldValues = FieldValues,
  TName extends Path<TFieldValues> = Path<TFieldValues>,
> extends HTMLAttributes<HTMLDivElement> {
  methods: UseFormReturn<TFieldValues>
  name: TName
  children: ReactNode
}

export function FormComponent<
  TFieldValues extends FieldValues = FieldValues,
  TName extends Path<TFieldValues> = Path<TFieldValues>,
>({
  methods,
  name,
  children,
  ...otherProps
}: FormComponentProps<TFieldValues, TName>) {
  return (
    <FormField
      control={methods.control}
      name={name}
      render={() => (
        <div {...otherProps}>
          <FormItem>
            {children}

            <FormMessage />
          </FormItem>
        </div>
      )}
    />
  )
}
© www.soinside.com 2019 - 2024. All rights reserved.