在Knex中为列设置别名时保留类型推断的可行方案
解决Knex联表查询带表名列别名的类型安全问题
当然有可行的方法来保留类型安全性!Knex的自动类型推断在遇到带表前缀的列别名时确实会“罢工”,不过我们可以通过显式定义查询结果类型或者基于原表类型做类型映射来解决这个问题,下面是具体的实现方式:
方法1:显式定义查询结果类型
最直接的方式是提前定义好联表查询后预期的结果类型,然后将其作为泛型参数传给knex():
// 先定义联表查询的结果类型 type JoinedRow = { id: number; aName: string; bName: string; }; // 传入自定义类型作为泛型参数 const joined = await knex<JoinedRow>("a") .join<BRow>("b", "primaryId", "foreignId") .select({ id: "primaryId", aName: "a.name", bName: "b.name" });
这样joined就会被正确推断为JoinedRow[]类型,完全保留类型检查能力,后续使用这些字段时IDE也会给出正确的提示。
方法2:基于原表类型做映射
如果不想重复定义字段类型,可以直接从原表的类型中提取对应字段的类型,这样当原表类型ARow或BRow更新时,结果类型也会自动同步:
// 从原表类型中映射出结果类型 type JoinedRow = { id: ARow["primaryId"]; aName: ARow["name"]; bName: BRow["name"]; }; // 同样传入这个映射后的类型 const joined = await knex<JoinedRow>("a") .join<BRow>("b", "primaryId", "foreignId") .select({ id: "primaryId", aName: "a.name", bName: "b.name" });
这种方式的好处是保持了类型的一致性,避免了原表类型更新后结果类型不同步的问题。
为什么原来的写法会丢失类型?
简单来说,Knex的类型推断系统只能解析不带表前缀的列名(比如"primaryId"),当你使用"a.name"这种带表名的字符串时,它没办法识别这个字符串对应的是ARow中的name字段,所以只能将推断结果设为any。显式定义结果类型相当于给Knex一个明确的“预期”,强制它按照我们定义的类型来处理查询结果。
内容的提问来源于stack exchange,提问作者Jonny
相关产品推荐
相关产品推荐

