【问题标题】:How to pass a generic type in a React component props如何在 React 组件 props 中传递通用类型
【发布时间】:2022-11-15 05:54:37
【问题描述】:

我有一个组件,它采用一组选项,定义如下:

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

并像这样实现:

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

在这个例子中,我提供了选择惯用手的选项,并且我已经为此定义了一个类型:

type DominantHand = "RIGHT" | "LEFT"

是否可以让MyComponent灵活地指定选项的类型?

我试过像下面这样完成这个,但显然这里的语法不正确:

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" }
  ]}
/>

有没有办法做到这一点?

【问题讨论】:

    标签: reactjs typescript typescript-generics


    【解决方案1】:

    在我阅读了official typescript documentation 之后,我会提出以下建议:

    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" },
          ]}
        />
      );
    };
    
    

    【讨论】:

      【解决方案2】:

      您应该在接口本身中定义泛型,以便可以将其传递给内部的对象。

      所以它应该是这样的:

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

      【讨论】:

      • 但我希望MyComponent 根据使用位置灵活。这将其强制为string,本质上与根本不使用泛型类型相同。
      • @BarryMichaelDoyle,你可以传递任何你想要的类型,我只是放一个字符串来说明它,你可以用任何类型替换string,它可以是numberboolean或你声明的任何类型,例如:如果您定义了类型 type SampleType = { key: string; anotherKey: boolean; },那么您也可以传递它:Props&lt;SampleType&gt;Props&lt;boolean&gt;、...等。
      【解决方案3】:

      试试

      interface Props<T> {
        options: <T>[]
      }
      

      然后你可以创建一个单独的选项对象并像这样传递它

      interface GenericPropObject {
      ....
      }
      
      function MyComponent(props: Props<GenericPropObject>) {...}
      

      【讨论】:

      • 我不太清楚你的意思,你能举个例子说明我如何使用相同的MyComponent组件并将它与两种不同的泛型类型一起使用吗?
      【解决方案4】:

      这里有点先进的这样做的方法(我在我正在从事的当前项目中所做的)

      在这里,我有一个 React 组件 TextInput,它显示 textpasswordemail 类型的输入。

      但是我要为使用此组件的任何人提供选项以确保提供的name 用于输入匹配他们的表单名称.

      所以,我的注册表单名称 types 看起来像这样。 (我是这样做的,所以我可以使用来自一个函数的所有输入的值更新状态,方法是使用每个输入组件将在输入时提供的名称)。

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

      然后,TextInput 道具。

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

      然后是 TextInput 组件本身

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

      所以要使用 TextInput 组件,你可以这样做

      <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
              />
      

      注意我在这里做了什么&lt;TextInput&lt;SignupInputNamesTypes&gt;我现在可以将我的 type 泛型传递给 TextInput 组件,然后使用它来设置可接受的 name 类型。

      这样做的好处是,它甚至不需要在使用 TextInput 组件时传递泛型。

      我希望这可以帮助那里的人。

      这就是它在 Storybook 上的样子。

      【讨论】:

        猜你喜欢
        • 2020-06-12
        • 1970-01-01
        • 2019-06-08
        • 1970-01-01
        • 1970-01-01
        • 2021-05-06
        • 1970-01-01
        • 1970-01-01
        • 2020-09-19
        相关资源
        最近更新 更多