使用泛型遇Type 'T'无法赋值给ReactNode错误,求排查解决
解决React泛型组件中Type 'T'无法赋值给ReactNode的错误
错误信息
Type 'T' is not assignable to type 'ReactNode'. Type 'T' is not assignable to type 'ReactPortal'.ts(2322) ModalSelect.tsx(17, 22): This type parameter might need an `extends React.ReactPortal` constraint. ModalSelect.tsx(17, 22): This type parameter might need an `extends React.ReactNode` constraint. index.d.ts(2379, 9): The expected type comes from property 'children' which is declared here on type 'DetailedHTMLProps<HTMLAttributes<HTMLParagraphElement>, HTMLParagraphElement>'
问题代码
接口定义:
export interface IModalSelect<T,E> { data: { id: number; name: string; data: { label: T; value: E; }[] }[]; title: string; onClose: () => void; }
组件实现:
function ModalSelect<T,E>({ data, title, onClose }: IModalSelect<T,E>) { const navigate = useNavigate(); const axiosPrivate = useAxiosPrivate(); return ( <Modal containerClass="modal-condition mdh" onClose={onClose}> <h2>{title}</h2> { data.map((el) => { return ( <div key={el.id}> <h3>Name: {el.name}</h3> <ul> { el.data.map((e, i) => { return ( <li key={i}> <p>{e.label}</p> </li> ) }) } </ul> </div> ) }) } </Modal> ) }
问题原因
React的<p>标签的children属性要求类型为React.ReactNode,但你定义的泛型T没有任何类型约束,TypeScript无法确认T是可以被React渲染的合法类型(比如string、number这类基础类型属于ReactNode,但如果T是任意类型就会触发报错)。你的业务场景中label和value为string或number,需要明确约束泛型的范围。
解决方案
给泛型T和E添加类型约束,限定它们只能是string或number(或者更宽泛的React.ReactNode,因为string和number都属于ReactNode的子类型):
精确约束(匹配你的业务场景)
修改后的接口:
import React from 'react'; export interface IModalSelect<T extends string | number, E extends string | number> { data: { id: number; name: string; data: { label: T; value: E; }[] }[]; title: string; onClose: () => void; }
修改后的组件:
import React from 'react'; import { useNavigate } from 'react-router-dom'; import { useAxiosPrivate } from './your-hook-path'; function ModalSelect<T extends string | number, E extends string | number>({ data, title, onClose }: IModalSelect<T,E>) { const navigate = useNavigate(); const axiosPrivate = useAxiosPrivate(); return ( <Modal containerClass="modal-condition mdh" onClose={onClose}> <h2>{title}</h2> { data.map((el) => { return ( <div key={el.id}> <h3>Name: {el.name}</h3> <ul> { el.data.map((e, i) => { return ( <li key={i}> <p>{e.label}</p> </li> ) }) } </ul> </div> ) }) } </Modal> ) }
宽松约束(支持未来扩展可渲染节点)
如果后续需要label支持JSX元素等其他可渲染内容,可将约束放宽到React.ReactNode:
export interface IModalSelect<T extends React.ReactNode, E extends string | number> { // 其余代码不变 }
添加约束后,TypeScript就能确认e.label是合法的React子节点类型,报错会自动消失。
内容的提问来源于stack exchange,提问作者oemer ok
相关产品推荐
相关产品推荐

