如何为多类型构建带字符串拼接的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("");
关键改动说明
AllTableColumns类型:
接收表名到表类型的映射对象,遍历每个表名,将表名与对应表的非函数字段拼接,生成符合格式的字段联合类型。IQuery泛型优化:
改为接收表名-类型映射作为泛型参数,每次调用InnerJoin时,会将新表的表名和类型添加到映射中,AllTableColumns会自动更新为包含所有关联表的带前缀字段。- 初始查询定义:
通过IQuery<{ TestA: TestA }>明确初始关联的表,确保初始Column参数就是TestA的带前缀字段。
修改后,调用Column时会得到完全符合期望的字段列表:
TestA.name TestA.id TestA.password TestB.id TestB.alies TestB.fullName TestB.parentId
内容的提问来源于stack exchange,提问作者Alen.Toma
相关产品推荐
相关产品推荐

