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

如何在TypeScript中定义含不同类型参数的泛型接口数组?

TypeScript泛型数组元素类型不固定的接口定义与实现方案

问题背景

我需要定义IGetInquiryProps接口,其中tableArray属性是IAntDataGridConvertedProps元素的数组,但数组中每个元素对应的IAntDataGridConvertedProps<T, K, G>泛型参数(T、K、G)并不固定,需要实现类型安全的泛型传递。

原始代码

export interface baseLazyParam {
  first?: number;
  rows: number;
  page: number;
  sortOrder?: number;
  sortField?: string;
}

export type extraPrams<InputQuery> = Omit<
  InputQuery,
  | 'sortingParams'
  | 'filterParam'
  | 'groupingColumns'
  | 'pageNumber'
  | 'pageSize'
>;

// 创建与BaseProperties键一致的映射类型
export type IFilter<T> = Record<keyof T, IFilterProperty>;

export type ILazyParam<InputQuery, selectedFilters> = baseLazyParam &
  extraPrams<InputQuery> & { filters: IFilter<selectedFilters> };

export interface IFilterProperty {
  operator: string;
  constraints: any[];
}

// 待修正的接口:泛型参数无法适配数组中元素的不同类型
export interface IGetInquiryProps <?,?,?>{
  headerCardGroupProps: any;
  footerCardGroupProps: any;
  tableArray: IAntDataGridConvertedProps<?,?,?>[];
  footerButtonsModalProps: any;
}

export interface IAntDataGridConvertedProps<T, K, G> {
  path?: string;
  ApiObj?: any;
  Columns?: any[];
  tbData?: G[];
  lazyParam?: ILazyParam<T, K>;
  recallApi?: boolean;
  // 其他属性...
}
// 期望的组件使用方式
const GetInquiryIndividualSamaCheque = forwardRef((props: IProps, ref) => {
  const { recordData, requestData, samaChequeSourceDetailId, showFooter } =
    props;
  const { getInquiryProps } = useLogicGetInquiryIndividualSamaCheque({
    ref,
    recordData,
    requestData,
    showFooter,
    samaChequeSourceDetailId,
  });

  return (
    <GetInquiry<
      [
        GetAllSamaChequeDetailControlsQuery,
        GetAllSamaChequeDetailControlsQuery,
      ],
      [
        selectedFiltersGetInquirySamaCheque,
        selectedFiltersGetInquirySamaCheque,
      ],
      [SamaChequeDetailControlViewModel, SamaChequeDetailControlViewModel]
    >
      {...getInquiryProps}
    </GetInquiry>
  );
});


// 待修正的组件定义
function GetInquiry<T, K, G>(props: IGetInquiryProps<T, K, G>) {
  const {
    headerCardGroupProps,
    footerCardGroupProps,
    tableArray,
    footerButtonsModalProps,
  } = props;

  return (
    <>
      {headerCardGroupProps && (
        <DataDisplayCardGroup {...headerCardGroupProps} />
      )}
      {tableArray?.map((tbData, index) => {
        return <AntDataGridConvert {...tbData} key={index} />;
      })}
      {footerCardGroupProps && (
        <DataDisplayCardGroup {...footerCardGroupProps} />
      )}
      {footerButtonsModalProps && (
        <FooterButtonsModal {...footerButtonsModalProps} />
      )}
    </>
  );
}

解决方案

核心思路是用元组类型承载每个数组元素对应的泛型参数集合,再通过TypeScript的映射类型将元组的每个索引对应到IAntDataGridConvertedProps的具体泛型实例,实现数组元素的类型安全。

简化示例验证

先通过简化示例理解实现逻辑:

// 父组件代码
import ChildComponent from '@pages/example/ChildComponent.tsx';

export interface A1 {
  a1: number;
}

export interface A2 {
  a2: number;
}

export interface B1 {
  b1: number;
}

export interface B2 {
  b2: number;
}

export interface C1 {
  data: {
    id: number;
    header: string;
    flag: boolean;
    title: string;
  }[];
}

export interface C2 {
  data: {
    id: number;
    header: string;
    flag: boolean;
    title: string;
  }[];
}

function ParentComponent() {
  const apiA1 = { a1: 1 };
  const paramsB1 = { b1: 1 };
  const tbDataC1 = {
    data: [
      {
        id: 101,
        header: '示例内容1',
        flag: true,
        title: '表格标题1',
      },
    ],
  };
  const apiA2 = { a2: 1 };
  const paramsB2 = { b2: 1 };
  const tbDataC2 = {
    data: [
      {
        id: 103,
        header: '示例内容3',
        flag: false,
        title: '表格标题3',
      },
    ],
  };
  return (
    <ChildComponent<[A1, A2], [B1, B2], [C1, C2]>
      tableArray={[
        { api: apiA1, params: paramsB1, tbData: tbDataC1 },
        { api: apiA2, params: paramsB2, tbData: tbDataC2 },
      ]}
    </ChildComponent>
  );
}

export default ParentComponent;
// 子组件代码
import AntDataGridConvert from '@/component/AntDataGrid/AntDataGridConvert.tsx';
import { IAntDataGridConvertedProps } from '@/component/AntDataGrid/types.ts';

export interface ITable<T, K, G> {
  api: T;
  params: K;
  tbData: G;
}

// 定义子组件接口:用元组T、K、G分别对应数组每个元素的三类泛型参数
export interface IChildComponent<
  T extends any[],
  K extends Record<keyof T, any>,
  G extends Record<keyof T, any>,
> {
  tableArray: { [I in keyof T]: ITable<T[I], K[I], G[I]> };
}

// 子组件实现
function ChildComponent<
  T extends any[],
  K extends Record<keyof T, any>,
  G extends Record<keyof T, any>,
>({ tableArray }: IChildComponent<T, K, G>) {
  return (
    <div>
      {( 
        tableArray as {
          [I in keyof T]: IAntDataGridConvertedProps<T[I], K[I], G[I]>;
        }
      )?.map((props, index) => {
        return <AntDataGridConvert {...props} key={index} />;
      })}
    </div>
  );
}

export default ChildComponent;

适配原问题的最终代码

将上述思路应用到原始问题中,修改IGetInquiryProps接口和GetInquiry组件:

// 修改后的IGetInquiryProps接口
export interface IGetInquiryProps<
  T extends any[],
  K extends Record<keyof T, any>,
  G extends Record<keyof T, any>
> {
  headerCardGroupProps: any;
  footerCardGroupProps: any;
  // 通过映射类型让数组每个元素对应各自的泛型参数
  tableArray: { [I in keyof T]: IAntDataGridConvertedProps<T[I], K[I], G[I]> };
  footerButtonsModalProps: any;
}

// 修改后的GetInquiry组件
function GetInquiry<
  T extends any[],
  K extends Record<keyof T, any>,
  G extends Record<keyof T, any>
>(props: IGetInquiryProps<T, K, G>) {
  const {
    headerCardGroupProps,
    footerCardGroupProps,
    tableArray,
    footerButtonsModalProps,
  } = props;

  return (
    <>
      {headerCardGroupProps && (
        <DataDisplayCardGroup {...headerCardGroupProps} />
      )}
      {tableArray?.map((tbData, index) => {
        return <AntDataGridConvert {...tbData} key={index} />;
      })}
      {footerCardGroupProps && (
        <DataDisplayCardGroup {...footerCardGroupProps} />
      )}
      {footerButtonsModalProps && (
        <FooterButtonsModal {...footerButtonsModalProps} />
      )}
    </>
  );
}

此时你可以按照最初期望的方式使用组件,TypeScript会自动校验tableArray中每个元素的泛型类型是否与传入的元组参数匹配。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.16 18:07:33