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

如何为多类型构建带字符串拼接的keyof类型?

问题分析

原代码中JoinNoneFunctionPropertyNames的核心问题在于:

  • 使用表名联合类型D与合并类型T & B的所有字段进行拼接,导致生成了表名与字段的无效交叉组合(如TestA.alies、TestB.name);
  • 未给初始表的字段添加对应表名前缀,不符合最终期望的格式规范。
解决方案

放弃通过T & B合并类型的思路,改用表名-类型映射追踪所有关联表的信息,通过遍历映射类型生成正确的表名.字段名联合类型。

修改后的完整代码:

export type NonFunctionPropertyNames<T> = { 
  [K in keyof T]: T[K] extends Function ? never : K 
}[keyof T];

// 遍历表名-类型映射,生成所有带表名前缀的字段联合
export type AllTableColumns<TableMap extends Record<string, object>> = {
  [TableKey in keyof TableMap]: `${TableKey & string}.${NonFunctionPropertyNames<TableMap[TableKey]>}`
}[keyof TableMap];

export interface IQuery<TableMap extends Record<string, object>> {
  Column: (columnName: AllTableColumns<TableMap>) => IQuery<TableMap>;
  InnerJoin: <NewTable extends string, B extends object>(
    tableName: NewTable,
    columnNameA: AllTableColumns<TableMap> | AllTableColumns<TableMap>[],
    columnNameB: NonFunctionPropertyNames<B> | NonFunctionPropertyNames<B>[]
  ) => IQuery<TableMap & { [K in NewTable]: B }>;
}

type TableNames = "TestA" | "TestB";

interface TestA {
  name: string;
  id: number;
  password: string;
}

interface TestB {
  fullName: string;
  id: number;
  alies: string;
  parentId: number;
}

// 初始查询:关联TestA表
const query = {} as IQuery<{ TestA: TestA }>;

// InnerJoin后,Column参数自动生成正确的带前缀字段联合
query.InnerJoin<"TestB", TestB>("TestB", "TestA.id", "parentId").Column("");
关键改动说明
  1. AllTableColumns类型:
    接收表名到表类型的映射对象,遍历每个表名,将表名与对应表的非函数字段拼接,生成符合格式的字段联合类型。
  2. IQuery泛型优化:
    改为接收表名-类型映射作为泛型参数,每次调用InnerJoin时,会将新表的表名和类型添加到映射中,AllTableColumns会自动更新为包含所有关联表的带前缀字段。
  3. 初始查询定义:
    通过IQuery<{ TestA: TestA }>明确初始关联的表,确保初始Column参数就是TestA的带前缀字段。

修改后,调用Column时会得到完全符合期望的字段列表:

TestA.name
TestA.id
TestA.password
TestB.id
TestB.alies
TestB.fullName
TestB.parentId

内容的提问来源于stack exchange,提问作者Alen.Toma

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 09:09:56