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

TypeScript中React组件能否无需额外泛型实现动态查找类型?

实现方案:单泛型下动态匹配onClick参数类型

完全可以只通过单个泛型TData实现你要的效果,核心是利用TypeScript的映射类型把idField和onClick的参数类型做关联,让TypeScript自动根据传入的idField推断对应类型,不需要额外添加泛型参数。

具体代码实现

首先定义你的IPerson接口:

interface IPerson {
  age: number;
  name: string;
}

然后修改组件的Props类型,通过映射类型生成联合类型,让idField和onClick的参数类型绑定:

import React from 'react';

type Props<TData> = {
  data: TData[];
} & {
  // 遍历TData的所有键,生成对应的idField和onClick组合
  [K in keyof TData]: {
    idField: K;
    onClick: (id: TData[K]) => void;
  };
}[keyof TData]; // 取映射后的所有值类型,组成联合类型

function DataList<TData>(props: Props<TData>) {
  return (
    <div>
      {props.data.map(item => (
        <div
          key={item[props.idField]}
          onClick={() => props.onClick(item[props.idField])}
        >
          {JSON.stringify(item)}
        </div>
      ))}
    </div>
  );
}

使用示例

当你传入idField="age"时,TypeScript会自动约束onClick的参数为number类型:

// 正确:onClick的id是number类型
<DataList
  data={[{ age: 25, name: 'Alice' }, { age: 30, name: 'Bob' }]}
  idField="age"
  onClick={(id) => {
    console.log(id.toFixed(2)); // id是number,支持number的方法
  }}
/>

当传入idField="name"时,参数自动变为string类型:

// 正确:onClick的id是string类型
<DataList
  data={[{ age: 25, name: 'Alice' }, { age: 30, name: 'Bob' }]}
  idField="name"
  onClick={(id) => {
    console.log(id.toUpperCase()); // id是string,支持string的方法
  }}
/>

如果尝试传入不匹配的类型,TypeScript会直接报错:

// 错误:onClick的id应该是number,但传入了string类型的处理逻辑
<DataList
  data={[{ age: 25, name: 'Alice' }]}
  idField="age"
  onClick={(id) => {
    console.log(id.toUpperCase()); // 类型错误:number没有toUpperCase方法
  }}
/>

原理说明

这里的关键是通过[K in keyof TData]遍历TData的所有键,为每个键生成一个包含idField: K和onClick: (id: TData[K]) => void的对象类型,然后通过[keyof TData]取所有这些对象类型组成联合类型。当你传入具体的idField值时,TypeScript会自动从联合类型中匹配对应的成员,从而约束onClick的参数类型。

内容的提问来源于stack exchange,提问作者r0n

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.14 23:30:58