You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用泛型遇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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.13 19:37:11