'How can I convert this JS function to TS?

I came across this JS function in react-hook-form docs:

import React from "react";
import { useForm } from "react-hook-form";

export default function Form({ defaultValues, children, onSubmit }) {
  const methods = useForm({ defaultValues });
  const { handleSubmit } = methods;

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {React.Children.map(children, child => {
        return child.props.name
          ? React.createElement(child.type, {
              ...{
                ...child.props,
                register: methods.register,
                key: child.props.name
              }
            })
          : child;
       })}
    </form>
  );
}

I want to convert it to TS. I tried following:

import React, {ReactNode} from "react";
import { SubmitHandler, useForm } from "react-hook-form";

interface RhfFormProps {
  defaultValues?: {}; 
  onSubmit: SubmitHandler<{}>;
  children?: ReactNode;
}

export default function Form({ defaultValues, children, onSubmit }: RhfFormProps) {
  const methods = useForm({ defaultValues });
  const { handleSubmit } = methods;

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {React.Children.map(children, (child) => {
        return child.props.name
          ? React.createElement(child.type, {
              ...{
                ...child.props,
                register: methods.register,
                key: child.props.name,
              },
            })
          : child;
      })}
    </form>
  );
}

But it gives following errors:

  1. For child variable:

    Object is possibly 'null' or 'undefined'.
    
  2. For props variable:

    Property 'props' does not exist on type 'string | number | boolean | {} | ReactElement<any, string | JSXElementConstructor<any>> | ReactPortal'.
    

Property 'props' does not exist on type 'string'.

How do I do this?

Update

As suggested in answer by Noah, I tried to introduce generics:

interface RhfFormProps<T> {
  defaultValues?: T; 
  onSubmit: SubmitHandler<T>;
  children?: ReactNode;
}

export default function Form<T>({ defaultValues, children, onSubmit }: RhfFormProps<T>) {
  const methods = useForm({ defaultValues });
  const { handleSubmit } = methods;

  return (
    <form onSubmit={handleSubmit(onSubmit)}>
      {React.Children.map(children, (child) => {
        return child.props.name
          ? React.createElement(child.type, {
              ...{
                ...child.props,
                register: methods.register,
                key: child.props.name,
              },
            })
          : child;
      })}
    </form>
  );
}

However, I still get some errors:

  1. On defaultValues:

    Type 'T' is not assignable to type 'UnpackNestedValue<DeepPartial<T>>'.
    
  2. Original error on child.props is not eliminated:

    Property 'props' does not exist on type 'string | number | boolean | {} | ReactElement<any, string | JSXElementConstructor<any>> | ReactPortal'.
    
  3. Error on child.type:

    Property 'type' does not exist on type 'string | number | boolean | {} | ReactElement<any, string | JSXElementConstructor<any>> | ReactPortal'.
    


Solution 1:[1]

  1. Do not use {} as a Type
  2. For child you have to do something like if (!child) return <p>Error</p>, else return <your code/>
  3. For props do not write out every parameter, try it like this:
interface RhfFormProps {
  defaultValues?: {}; 
  onSubmit: SubmitHandler<{}>;
  children?: ReactNode;
}

export default function Form(props: RhfFormProps) {
    ...yourCode
}
  1. I think you should google for Typescript Generics

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Noah Buchmann