首页 > 解决方案 > React 组件中的可选泛型

问题描述

下面的代码有两个问题。

interface MyForm {
  age: number;
  email: string;
  name: string;
}

function Form<
  T,
  ComponentProps extends {
    name: string;
    onChange: (event: React.ChangeEvent) => void;
  }
>(
  props: {
    component:
      | React.ComponentClass<ComponentProps>
      | React.ComponentType<ComponentProps>;
    name: keyof T;
  } & Omit<ComponentProps, "name" | "onChange">
) {
  const { component: Component, name, ...rest } = props;

  const handleChange = () => {
    //
  };

  return <Component {...(rest as any)} name={name} onChange={handleChange} />;
}

function Component(props: {
  name: string;
  onChange: (event: React.ChangeEvent) => void;
  color: "blue" | "yellow";
}) {
  const { color, name, onChange } = props;
  return <input name={name} onChange={onChange} style={{color}} />;
}

function App() {
  return (
    <>
      {/* in this code, the name is not checked */}
      <Form color="blue" component={Component} name="something" />
      {/* in this code, the name is checked, but I must define all generics */}
      <Form<MyForm, React.ComponentProps<typeof Component>>
        color="yellow"
        component={Component}
        name="name"
      />
      {/* this doesn't work */}
      <Form<MyForm> color="blue" component={Component} name="email" />
    </>
  );
}

起初,我想像这样调用 Form 组件,<Form<MyForm> color="blue" component={Component} name="email" />而不是定义第二个泛型。在一个复杂的组件中,我有更多的属性和更多的泛型,我不想强​​制其他程序员定义所有泛型,因为我希望name必须匹配MyForm. 这就是目标,name必须由 TypeScript 检查并且必须是 keyof MyForm。我知道我可以使用可选泛型并定义默认类型,但它破坏了逻辑,然后color在调用Form. 而且我不能定义颜色是必需的,因为逻辑是,component必须具有nameonChange属性,我不关心其余的,只是将其余的传递给组件。

其次,我无法摆脱任何 in {...(rest as any)}。我不知道,为什么我只使用{...rest}.

标签: reactjstypescript

解决方案


似乎您在第一个问题中要求的是让<Form>组件的用户能够指定一些通用参数,(例如<Form<MyFormInterface> />,并且让打字稿仍然推断其余的参数(例如传递给的组件的道具)财产component)。

不幸的是,目前不支持这 - 类型推断是一个全有或全无的命题 - 打字稿推断一切,或者用户指定一切。有一个非常受欢迎的 github issue 要求提供这个确切的功能。另请参阅此答案以获得更通用的解释。


推荐阅读