如何用React+TypeScript动态创建组件?解决ComponentType类型报错
React + TypeScript 动态创建组件的正确姿势
问题场景
如何使用React与TypeScript动态创建组件?假设已有RandomComponent,并将其作为props传入renderInput函数,如何从该函数中返回<RandomComponent>?
最初的代码TypeScript无法识别:
export const renderInput = (props) => { const Field: JSX.Element = props.component; return ( <Field {...props} /> ) }
补充说明:
已经让代码运行起来了,但想了解添加ComponentType类型后的写法。不加该类型时代码正常运行,但添加后代码如下:
const Field: ComponentType = component; return ( <Field name={name} label={label} value={value} onChange={onChange} {...props} /> ); };
此时出现报错:
TS2322: Type '{ name: any; label: any; value: any; onChange: any; }' is not assignable to type 'IntrinsicAttributes'. Property 'name' does not exist on type 'IntrinsicAttributes'
问题根源
- 类型声明错误:把
props.component声明为JSX.Element是完全错误的——JSX.Element是组件渲染后生成的实例对象,而组件本身是函数或类,属于ComponentType类型范畴。 - 泛型缺失:直接使用
ComponentType而不指定泛型时,TypeScript默认认为该组件只接受IntrinsicAttributes(无自定义props),所以你传入name/label等属性时会触发类型不匹配报错。
正确解决方案
核心是给ComponentType传入对应的props类型泛型,明确组件接受的参数结构:
1. 先定义组件的Props类型
声明动态组件需要接收的props结构:
// 定义组件所需的Props类型 type InputFieldProps = { name: string; label: string; value: string; onChange: (value: string) => void; // 可添加其他需要传递的props };
2. 给renderInput函数指定完整类型
import { ComponentType } from 'react'; export const renderInput = (props: { component: ComponentType<InputFieldProps> } & InputFieldProps) => { // 拆分props,避免把component本身传递给子组件 const { component: Field, ...restProps } = props; return <Field {...restProps} />; };
3. 简化写法(自动推导类型)
如果不想显式处理变量,也可以直接解构时重命名,TypeScript会自动推导类型:
import { ComponentType } from 'react'; type InputFieldProps = { name: string; label: string; value: string; onChange: (value: string) => void; }; export const renderInput = ({ component: Field, ...rest }: { component: ComponentType<InputFieldProps> } & InputFieldProps) => { return <Field {...rest} />; };
补充说明
之前不加类型能运行,是因为TypeScript处于隐式any模式,不会做严格的类型校验,但这种写法丢失了TypeScript的类型安全优势,上线后容易出现props不匹配的隐性bug。
内容的提问来源于stack exchange,提问作者funnyguy
相关产品推荐
相关产品推荐

