DEV Community

Cover image for Passing Props to Child Components in React using TypeScript
Francisco Mendes
Francisco Mendes

Posted on

Passing Props to Child Components in React using TypeScript

I believe that if you are reading this article, you already have an idea of component hireraquia and the normal flow is to pass props from the parent component to the child component.

I believe we all had some friction trying to convert our JavaScript knowledge to TypeScript, even though it was the same the code became more verbose and suddenly you started questioning everything.

I continue with several challenges on a daily basis, however today I am fully aware of the advantages that TypeScript brings to my application development experience in React.

Exactly today I'm going to give a brief example of how we can pass props between components using TypeScript.

Let's code

Pretend that the main page of your application is as follows:

// @src/App.tsx

import React, { useState } from "react";

import Form from "./components/Form";

const App = () => {
  const [state, setState] = useState("");
  const handleOnSubmit = (e) => {
    e.preventDefault();
    console.log({ state });
  };
  return (
    <Form
      state={state}
      setState={setState}
      handleOnSubmit={handleOnSubmit}
      placeholder="Type some letters"
    />
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

And the component of our form is as follows:

// @src/components/Form.tsx

import React from "react";

const Form = ({
  state,
  setState,
  handleOnSubmit,
  placeholder,
}) => {
  return (
    <form onSubmit={handleOnSubmit}>
      <input
        type="text"
        value={state}
        onChange={(e) => setState(e.target.value)}
        placeholder={placeholder}
      />
      <button type="submit">Submit</button>
    </form>
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

As you may have noticed both components, both are written the same way you would in JavaScript. And you may have noticed that we passed the following properties from the parent component to the child component:

  • state is a string;
  • setState is a function;
  • handleOnSubmit is a function;
  • placeholder is a string;

But before that we have to type our own function components. This way:

// @src/App.tsx

const App: React.FC = () => {
  // Hidden for simplicity
}


// @src/components/Form.tsx

const Form: React.FC = () => {
  // Hidden for simplicity
}
Enter fullscreen mode Exit fullscreen mode

So we can go to our Form.tsx and create a type called Props that will be used as a generic for our component.

// @src/components/Form.tsx

import React from "react";

type Props = {
  state: string;
  setState: (val: string) => void;
  handleOnSubmit: () => void;
  placeholder: string;
};

const Form: React.FC<Props> = ({
  state,
  setState,
  handleOnSubmit,
  placeholder,
}) => {
  return (
    // Hidden for simplicity
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

You may have noticed an inconsistency in the previous code, in App.tsx the handleOnSubmit function takes a single argument, which is an event.

While in our Props type of Form.tsx we don't have any arguments. For this we will use a React data type called FormEvent that will have a generic, which in this case will be the HTMLFormElement.

This way we will already have the ideal data type to "handle" the form event.Like this:

// @src/components/Form.tsx

import React, { FormEvent } from "react";

type SubmitEvent = FormEvent<HTMLFormElement>;

type Props = {
  state: string;
  setState: (val: string) => void;
  handleOnSubmit: (e: SubmitEvent) => void;
  placeholder: string;
};

const Form: React.FC<Props> = ({
  state,
  setState,
  handleOnSubmit,
  placeholder,
}) => {
  return (
    // Hidden for simplicity
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

This way, you must have also noticed that in the input element we have an attribute that is the onChange which is actually an event, so we have to type it.

In a very similar way to what we did before. First we will import a React data type called ChangeEvent, then we will assign a generic which in this case will be HTMLInputElement. This way:

// @src/components/Form.tsx

import React, { ChangeEvent, FormEvent } from "react";

type SubmitEvent = FormEvent<HTMLFormElement>;
type InputEvent = ChangeEvent<HTMLInputElement>;

// Hidden for simplicity

const Form: React.FC<Props> = ({
  // Hidden for simplicity
}) => {
  return (
    <form onSubmit={handleOnSubmit}>
      <input
        type="text"
        value={state}
        onChange={(e: InputEvent) => setState(e.target.value)}
        placeholder={placeholder}
      />
      <button type="submit">Submit</button>
    </form>
  );
};

export default Form;
Enter fullscreen mode Exit fullscreen mode

Now we can go back to our App.tsx. We just need to create a type in the handleOnSubmit function argument, which, as you might have guessed, is an event. Like this:

// @src/App.tsx

import React, { useState } from "react";

import Form from "./components/Form";

type FormEvent = React.FormEvent<HTMLFormElement>;

const App: React.FC = () => {
  const [state, setState] = useState("");
  const handleOnSubmit = (e: FormEvent) => {
    e.preventDefault();
    console.log({ state });
  };
  return (
    // Hidden for simplicity
  );
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Finally we can add a generic to our useState(), which in this case is a string.

// @src/App.tsx

import React, { useState } from "react";

// Hidden for simplicity

const App: React.FC = () => {
  const [state, setState] = useState<string>("");
  // Hidden for simplicity
};

export default App;
Enter fullscreen mode Exit fullscreen mode

Conclusion

As always, I hope I was clear and that I helped you. If you notice any errors in this article, please mention them in the comments. ✏️

Hope you have a great day! 🙌 🤩

Top comments (4)

Collapse
 
gerreth profile image
Gerret Halberstadt

Hey, while in your example it makes sense to give the component an implicit children prop, in the article above it might be misleading. Someone could be using something like

<Form
  state={state}
  setState={setState}
  handleOnSubmit={handleOnSubmit}
  placeholder="Type some letters"
>
  Some info text
</Form>
Enter fullscreen mode Exit fullscreen mode

and wondering why the text is not rendering without TypeScript complaining. You could instead write it like

const Form = ({state, setState, handleOnSubmit, placeholder}: Props) => {
  // ...
}
Enter fullscreen mode Exit fullscreen mode

and do not lose something too useful. I stumbled upon github.com/typescript-cheatsheets/... (Why is React.FC discouraged?) a while ago and thought it could be useful to share here.

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thanks for sharing! Undoubtedly a good resource to study. 🤓

Collapse
 
franciscomendes10866 profile image
Francisco Mendes

Thanks for your comment! It's a great addition to the knowledge shared in the article! 🤩

Collapse
 
moroix profile image
Bilal • Edited

emailsjs no longer use UserID they use publicKey instead