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

TypeScript函数式领域驱动设计中Query映射类型的作用解析

解析TypeScript映射类型定义的Query类型

一、Query类型到底怎么工作?

先拆解这段类型代码:

type Query<T> = {
  [k: keyof T]: { operator: Operator, value: unknown },
}
  • keyof T:提取泛型参数T的所有属性名。比如T是{id: string, name: string, age: number},那keyof T就是"id" | "name" | "age"这个联合类型。
  • [k: keyof T]:这是TypeScript映射类型的核心语法,相当于遍历T的每一个属性名k,为每个k自动生成对应的属性结构。
  • 每个属性对应的{ operator: Operator, value: unknown }:规定查询某个字段时,必须传入包含操作符(比如等于/大于/包含这类,文章里应该有定义Operator的具体取值)和匹配值的对象。

举个实际例子,假设领域实体是用户:

type User = { id: string; name: string; age: number };

那Query<User>会自动生成对应的查询类型:

type UserQuery = {
  id: { operator: Operator; value: unknown };
  name: { operator: Operator; value: unknown };
  age: { operator: Operator; value: unknown };
};

这时候你写查询条件时,只能用User里存在的属性,比如{ age: { operator: "gt", value: 18 } },要是瞎写个address这类不存在的字段,TypeScript会直接报错拦截。

二、在Repository场景下的优势

  1. 杜绝低级错误:新手常犯的属性名拼写错误(比如把age写成ag)会被编辑器立刻检测到,不用等到运行时才发现查不到数据。
  2. 适配所有实体,减少重复代码:不管Repository操作的是用户、订单还是商品,Query类型都会跟着实体的属性自动生成对应的查询结构,不用为每个实体单独写一套查询类型。
  3. 强制查询格式统一:所有人写查询都必须遵循{ 字段名: { operator: ..., value: ... } }的格式,不会出现有人直接传{ age: 18 },有人传{ age: { val: 18 } }这种混乱写法,后续getMatching方法的处理逻辑也能统一。
  4. 贴合DDD领域纯净性:在领域驱动设计中,Repository是领域层和数据层的桥梁,这种类型约束能保证所有查询都严格围绕领域实体的属性展开,不会出现与领域无关的查询条件,避免污染领域模型。

小优化建议

原代码里的value: unknown可以改成value: T[k],这样匹配值的类型会和实体属性的类型严格对应。比如User的age是number,那value就必须传number,不能传字符串,进一步提升类型安全性:

type Query<T> = {
  [k: keyof T]: { operator: Operator; value: T[k] };
};

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.29 16:58:40