首页 > 解决方案 > 将 React 子组件实现为只有特定组件时如何解决类型问题?

问题描述

我正在尝试实现一种 React 子组件验证以仅具有特定组件但面临类型问题。

请在下面查看我的代码:

// a component needs the validation

import { Children, FunctionComponent, isValidElement } from 'react';
import { AccordionProps } from '@components/old/signup/organisms/accordion/interfaces';
import CheckFormField from '@components/old/signup/organisms/checkFormField';
import AccordionHeader from '@components/old/signup/organisms/accordionHeader';


const Accordion: FunctionComponent<AccordionProps> = ({ children }) => {
                                                                                             
const allowedComponents = [CheckFormField, AccordionHeader]; // these can only be children

Children.map(children, (child) => {
    const childType = isValidElement(child) && child.type;
    if (!allowedComponents.includes(childType)) { // here comes type error to use includes method
      throw new Error('Error message..');
    }
  });
                            :
                            :
return (
  <div>{children}</div>
);

上面代码的类型错误:

TS2345: Argument of type 'string | false | JSXElementConstructor<any>' is not assignable to parameter of type 'FunctionComponent<CheckFormFiledProps> | FunctionComponent<AccordionHeaderProps>'.   Type 'string' is not assignable to type 'FunctionComponent<CheckFormFiledProps> | FunctionComponent<AccordionHeaderProps>'.

以及我在下面定义的道具:

// interfaces.ts

export interface AccordionProps {
  children: ReactElement<any> | ReactElement[];
}

我怀疑上面的儿童道具可能不是合适的类型,但到目前为止没有运气搜索它。

参考:

在反应组件中只允许特定类型的子级

在 React 和 Typescript 中只允许特定组件作为子组件

提前致谢。

标签: reactjstypescript

解决方案


对此的一种可能解决方案是通过组件属性而不是 classicchildren将目标子组件传递给父组件。让我们调用子组件属性Components,以区别于标准children

下面是子组件数组是如何验证(由 TypeScript 本身)并通过Main组件呈现的:

// Main.tsx

import ValidChildOne from './ValidChildOne';
import ValidChildTwo from './ValidChildTwo';

// declaring what is allowed as children
type AllowedChild = typeof ValidChildOne | typeof ValidChildTwo;

interface MainProps {
  Components: AllowedChild[];  // array
}

export default function Main({ Components }: MainProps) {
  return (
    <>
      <h1>Main</h1>
      {
        Components.map((Child, index) => <Child key={index} />)
      }
    </>
  );
}

以下是Main组件(及其道具)的应用方式:

// App.tsx

import Main from './Main';
import ValidChildOne from './ValidChildOne';
import ValidChildTwo from './ValidChildTwo';

export default function App() {
  return (
    <Main Components={[ValidChildOne, ValidChildTwo]} />
  );
}

最后,子组件的代码供参考:

// ValidChildOne.tsx

export default function ValidChildOne() {
  return <h2>ValidChildOne</h2>;
}
// ValidChildTwo.tsx

export default function ValidChildTwo() {
  return <h2>ValidChildTwo</h2>;
}

推荐阅读