igorludi
igorludi

Reputation: 1581

How to cast query results to generated types?

I have my types generated for pg database via kysley-codegen and it generates this interface for my QuestionReview table:

export interface QuestionReview {
  id: Generated<number>;          // this will be a problem
  idQuestion: number;
  idUserReviewed: number;
  tsCreated: Timestamp;           // this will be a problem
  tsModified: Timestamp;          // this will be a problem
  userModified: string;
}

Now, in my service class I'm inserting into this table and want to return the newly inserted entity as Promise<QuestionReview>. Here is the code:

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

which returns the rv object with these JS types:

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

I can not just return this object because TS cannot cast:

I've ended up returning this rather humiliating object with brute-force casting:

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

What am I doing wrong, is there a better way to return strongly typed inserted entity?

Upvotes: 0

Views: 95

Answers (1)

Lesiak
Lesiak

Reputation: 25976

Use the use the Selectable, Insertable and Updateable wrappers.

Consult the Kysely docs:

// You should not use the table schema interfaces directly. Instead, you should
// use the `Selectable`, `Insertable` and `Updateable` wrappers. These wrappers
// make sure that the correct types are used in each operation.
//
// Most of the time you should trust the type inference and not use explicit
// types at all. These types can be useful when typing function arguments.
export type Person = Selectable<PersonTable>
export type NewPerson = Insertable<PersonTable>
export type PersonUpdate = Updateable<PersonTable>

In your case:

import {
  ColumnType,
  Generated,
  Insertable,
  JSONColumnType,
  Selectable,
  Updateable,
} from 'kysely'

// Generated
export type Timestamp = ColumnType<Date, Date | string, Date | string>;

// Generated
export interface QuestionReview {
  id: Generated<number>;          // this will be a problem
  idQuestion: number;
  idUserReviewed: number;
  tsCreated: Timestamp;           // this will be a problem
  tsModified: Timestamp;          // this will be a problem
  userModified: string;
}

export type QuestionReviewSelectable = Selectable<QuestionReview>

QuestionReviewSelectable is inferred to:

type QuestionReviewSelectable = {
    id: number;
    idQuestion: number;
    idUserReviewed: number;
    tsCreated: Date;
    tsModified: Date;
    userModified: string;
}

TS Playground example

Upvotes: 1

Related Questions