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

如何在TypeScript中为ORM关联查询条件实现强类型定义?

实现关联查询的WHERE条件类型定义方案

一、可行方案:实现属性名拼接的类型定义

可以通过TypeScript的递归类型和模板字符串,实现支持点分隔的关联属性路径类型,同时兼容操作符逻辑。

核心类型定义

先实现递归生成属性路径的类型,将嵌套属性转换为点分隔的字符串格式:

// 提取对象的属性键,排除符号类型
type ObjectKeys<T> = T extends object ? Exclude<keyof T, symbol> : never;

// 递归生成属性路径:支持嵌套对象的点分隔写法
type Path<T, D extends number = 10> = [D] extends [never]
  ? never
  : T extends object
  ? {
      [K in ObjectKeys<T>]: K extends string
        ? `${K}` | `${K}.${Path<T[K], Prev[D]>}`
        : never;
    }[ObjectKeys<T>]
  : never;

// 递归深度递减的辅助类型,控制最大嵌套层级
type Prev = [never, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10];

接着定义支持操作符的条件值类型:

// 支持等值、模糊匹配、范围比较等操作的条件类型
type ConditionValue<T> = T | {
  eq?: T;
  like?: string;
  lt?: T extends number ? T : never;
  gt?: T extends number ? T : never;
  // 可根据业务需求扩展更多操作符
};

最后组合成完整的WHERE条件类型:

type WhereCondition<T> = {
  [K in Path<T>]?: ConditionValue<T extends { [key in K]: infer V } ? V : never>;
} & {
  // 支持AND/OR逻辑组合
  AND?: WhereCondition<T>[];
  OR?: WhereCondition<T>[];
};

应用到你的模型

interface Model1{
    id:string;
    name:string;
    childId:string;
}
interface Model1Relations{
    child:Model2;
}
type Model1WithRelations = Model1 & Model1Relations;
interface Model2{
    id:string;
    name:string;
}

// 生成Model1的查询条件类型
type Model1Where = WhereCondition<Model1WithRelations>;

// 合法使用示例
const validQuery: Model1Where = {
  "name": "Bob",
  "child.name": { like: "%Alice%" },
  AND: [
    { "id": "123" },
    { "child.id": { gt: "456" } }
  ]
};

该方案完全支持"child.name"这类点分隔的属性路径写法,同时保留操作符和逻辑组合的类型检查,解决了嵌套写法可读性差的问题。

二、替代方案:兼容两种写法的类型合并

如果递归路径类型的复杂度超出预期,可以同时支持点分隔和嵌套两种写法,通过类型合并实现灵活选择:

// 嵌套式条件类型
type NestedWhere<T> = {
  [K in ObjectKeys<T>]?: T[K] extends object
    ? ConditionValue<T[K]> | NestedWhere<T[K]>
    : ConditionValue<T[K]>;
} & { AND?: NestedWhere<T>[]; OR?: NestedWhere<T>[] };

// 合并点分隔和嵌套两种写法
type HybridWhere<T> = WhereCondition<T> | NestedWhere<T>;

这样用户既可以用{"child.name": "Bob"},也可以用{child: {name: "Bob"}},兼顾类型安全和使用灵活性。

三、注意事项

  • 递归深度:Path类型的D参数控制最大嵌套层级,默认10层,可根据实际关联深度调整。
  • 特殊类型处理:如果模型包含数组、函数等非对象类型,需要在ObjectKeys中进一步排除,避免生成无效路径。
  • 性能优化:极端复杂的模型可能导致TypeScript类型检查变慢,可通过限制递归深度或拆分类型缓解。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.04 02:50:29