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

如何将Kysley查询结果转换为自动生成的类型?

Kysley插入数据后返回强类型实体的问题与优化方案

问题描述

我通过kysley-codegen为PostgreSQL数据库生成了类型,其中QuestionReview接口定义如下:

export interface QuestionReview {
  id: Generated<number>;          // 存在类型不匹配问题
  idQuestion: number;
  idUserReviewed: number;
  tsCreated: Timestamp;           // 存在类型不匹配问题
  tsModified: Timestamp;          // 存在类型不匹配问题
  userModified: string;
}

在服务类中,我向该表插入数据后,希望返回Promise<QuestionReview>类型的新插入实体,实现代码如下:

const rv = await this.db
      .insertInto('questionReview')
      .values({
        idQuestion: idQuestion,
        idUserReviewed: idAppUser,
      } as Insertable<QuestionReview>)
      .returningAll()
      .executeTakeFirstOrThrow();

实际执行后,返回的rv对象的JavaScript运行时类型为:

{
  id: number,
  ...
  tsCreated: Date,
  tsModified: Date
}

由于TypeScript无法自动完成以下类型转换,我无法直接返回该对象:

  • number 转换为 Generated<number>
  • Date 转换为 Timestamp

目前我只能通过强制类型转换的方式返回:

return {
  ...rv,
  id: rv.id as unknown as Generated<number>,
  tsCreated: rv.tsCreated as unknown as Timestamp,
  tsModified: rv.tsModified as unknown as Timestamp,
};

请问我的做法是否有误?有没有更优的方法返回强类型的插入实体?


解决方案

你的做法本身没有错误,但可以通过以下几种方式简化或优化:

1. 直接对整个对象做类型断言

Kysley的Generated<T>只是编译时标记字段为数据库自动生成,运行时实际值就是T类型;Timestamp在运行时本质上就是Date。因此你不需要逐个字段转换,直接对整个对象做断言即可:

return rv as unknown as QuestionReview;

这种方式更简洁,且和逐个字段转换的效果完全一致——因为运行时类型完全匹配,只是编译时需要对齐类型定义。

2. 定义专用的运行时类型(提升可读性)

如果觉得直接断言不够清晰,可以先定义一个和数据库实际返回结构一致的类型,再转换为目标类型:

// 定义和运行时返回结构匹配的类型
type QuestionReviewRuntime = Omit<QuestionReview, 'id' | 'tsCreated' | 'tsModified'> & {
  id: number;
  tsCreated: Date;
  tsModified: Date;
};

// 插入时先断言为运行时类型
const rv = await this.db
  .insertInto('questionReview')
  .values({ idQuestion, idUserReviewed } as Insertable<QuestionReview>)
  .returningAll()
  .executeTakeFirstOrThrow() as QuestionReviewRuntime;

// 转换为目标接口类型
return rv as unknown as QuestionReview;

这种方式能更清晰地区分编译时类型定义和运行时实际类型,同时保持代码简洁。

3. 调整kysley-codegen生成配置

检查kysley-codegen的配置项,看是否可以调整类型映射规则:

  • 对于Timestamp类型,可尝试配置将其直接映射为Date(例如设置timestampType: 'Date',具体看代码生成工具的文档),这样生成的QuestionReview接口中时间字段的类型就是Date,避免类型转换。
  • 对于Generated<T>,它是Kysley用于标记插入时无需提供字段的编译时类型,运行时不存在对应的实体类型,因此无论如何都需要编译时的类型断言来对齐。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.18 20:05:12