Search code examples
reactjstypescriptreact-hook-formreact-typescript

Typescript React How to add an a second interface to Prop


import { ReactNode, DetailedHTMLProps, FormHTMLAttributes } from "react";
import {
  FieldValues,
  SubmitHandler,
  useForm,
  UseFormReturn,
} from "react-hook-form";

// I want to add this type to the FormProps interface
// DetailedHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement>

interface FormProps<TFormValues extends FieldValues> {
  onSubmit: SubmitHandler<TFormValues>;
  children: (methods: UseFormReturn<TFormValues>) => ReactNode;
}

export const Form = <TFormValues extends Record<string, any>>({
  onSubmit,
  children,
}: FormProps<TFormValues>) => {
  const methods = useForm<TFormValues>();

  return (
    <form onSubmit={methods.handleSubmit(onSubmit)}>{children(methods)}</form>
  );
};


I'm trying to add the DetailedHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> data type for the form not sure what's the right way of doing that.


Solution

  • Use extends to say that the FormProps interface is made of the same content as your desired type, as well as extra properties that you specify.

    Make sure not to collide the property names, or if you do so intentionally, the collided properties must have compatible types. In your case, onSubmit and children collide with properties in DetailedHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> and have incompatible types; you could just use different names instead.

    interface FormProps<TFormValues extends FieldValues> extends
        DetailedHTMLProps<FormHTMLAttributes<HTMLFormElement>, HTMLFormElement> {
        // Make sure not to collide properties with incompatible types
        submitHandler: SubmitHandler<TFormValues>;
        methodsHandler: (methods: UseFormReturn<TFormValues>) => ReactNode;
    }
    
    export const Form = <TFormValues extends Record<string, any>>({
        submitHandler,
        methodsHandler,
        ...formAttrs
    }: FormProps<TFormValues>) => {
        const methods = useForm<TFormValues>();
    
        return (
            <form onSubmit={methods.handleSubmit(submitHandler)} {...formAttrs}>{methodsHandler(methods)}</form>
        );
    };
    

    Playground Link