Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to pass a generic type in a React component props

I have a component that takes an array of options which is defined as follows:

interface Props {
  options: {
    label: string;
    value: string;
  }[]
}
function MyComponent(props: Props) {...}

And implemented like this:

<MyComponent
  options={[
    { label: "Right Hand", value: "RIGHT" },
    { label: "Left Hand", value: "LEFT" }
  ]}
/>

In this example I give options to select a dominant hand and I've defined a type for that like this:

type DominantHand = "RIGHT" | "LEFT"

Is it possible to make MyComponent flexible to specify the type of options?

I've tried to accomplish this like the following but obviously the syntax isn't correct here:

type DominantHand = "RIGHT" | "LEFT"
type Gender = "MALE" | "FEMALE"

interface Props {
  options<T>: { // this syntax is wrong
    label: string;
    value: T;
  }[]
}
function MyComponent(props: Props) {...}

...

<MyComponent
  options<DominantHand>={[ // <--- this syntax is wrong
    { label: "Right Hand", value: "RIGHT" },
    { label: "Left Hand", value: "LEFT" }
  ]}
/>
<MyComponent
  options<Gender>={[ // <--- this syntax is wrong
    { label: "Male", value: "MALE" },
    { label: "Female", value: "FEMALE" }
  ]}
/>

Is there a way to accomplish this?

like image 562
Barry Michael Doyle Avatar asked Nov 24 '25 22:11

Barry Michael Doyle


2 Answers

After I have read the official typescript documentation I would suggest the following:

function MyComponent<T>(props: {
  options: {
    label: string;
    value: T;
  }[];
}) {
  return <div>MyComponent</div>;
}


type DominantHand = "RIGHT" | "LEFT";

function ParentComponent() {
  return (
    <MyComponent<DominantHand>
      options={[
        { label: "Right Hand", value: "RIGHT" },
        { label: "Left Hand", value: "LEFT" },
      ]}
    />
  );
};

like image 164
rjumatov Avatar answered Nov 27 '25 13:11

rjumatov


Here is a somewhat advanced way to do it (which I did in the current project I am working on)

Here, I have a React component TextInput which displays inputs of types text, password, or email.

But, I want to give anyone using this component the option to make sure the supplied name for the input matches their form names.

So, My Signup Form name types looks like this. ( I did it this way, so I can update the state with values from all the inputs from one function, by using the names each input component will provide on input ).

type SignupInputNamesTypes =
  | "email"
  | "username"
  | "first_name"
  | "last_name"
  | "password"
  | "password_confirm"
  | "referrer";

Then, the TextInput props.

export interface TextInputProps<NameTypes> {
 name: NameTypes;
 type: "text" | "password" | "email";
...
...
...
}

Then the TextInput component itself

export default function TextInput<NameTypes>({
  label,
  name,
  value = "",
  type = "text",
  infoText = "",
  showChecked = false,
  handleChange,
  required = false,
  cssClasses,
}: TextInputProps<NameTypes>): JSX.Element {
  return (
    <>
     ...
     ...
     ...
    </>
)};

So to use the TextInput component, you do something like this

<TextInput<SignupInputNamesTypes>
          type="text"
          cssClasses="flex-1"
          value={state.first_name}
          label={__("First Name", "referrer-plugin")}
          name="first_name"
          handleChange={(value, event) => {
            handleChange("first_name", value);
          }}
          required
        />

Notice what I did here <TextInput<SignupInputNamesTypes> I am now able to pass my type generic to the TextInput component, which is then used to set the acceptable name types.

And the beauty of this is that it's not even required to pass along the generic while using the TextInput component.

I hope this helps someone out there.

This is what it looks like on Storybook.

enter image description here

like image 28
Henry Obiaraije Avatar answered Nov 27 '25 15:11

Henry Obiaraije



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!