import type { Compilable, InferResult, Kysely } from 'kysely'; type QueryResultSuccess<T> = { success: true; data: T; }; type QueryResultError = { success: false; errorMsg: string; }; type QueryResult<T> = QueryResultSuccess<T> | QueryResultError; type AsyncQueryResult<T> = Promise<QueryResult<T>>; type DB = { product: { id: number; name: string; }; }; class Datasource<TDatabase = DB> { constructor(public kysely: Kysely<TDatabase>) {} query = async <TFn extends () => any, TData = ReturnType<TFn>>( fn: TFn ): AsyncQueryResult<TData> => { return this.createQueryResultSuccess<TData>(fn()); }; queryKysely = async < TQuery extends Compilable<unknown>, TData = InferResult<TQuery>, >( query: TQuery ): AsyncQueryResult<TData> => { try { const r = await this.kysely.executeQuery(query); return this.createQueryResultSuccess<TData>(r.rows as TData); } catch (err) { return this.createQueryResultError(err as Error); } }; protected createQueryResultSuccess = <T>(data: T): QueryResultSuccess<T> => { return { success: true, data: data, }; }; protected createQueryResultError = (err: Error): QueryResultError => { return { success: false, errorMsg: err.message, }; }; } type Product = { id: number; name: string; description: string; }; class Repo { constructor(private ds: Datasource) {} search = async (): AsyncQueryResult<Product[]> => { // ts-expect-error shoudl give an error cause id aren't the same types type IncompleteProduct = { id: number; name: string; }; const incompleteProduct: IncompleteProduct = { id: 1, name: 'Incomplete Product', }; const getIncompleteProducts = (): IncompleteProduct[] => { return [incompleteProduct]; }; return this.ds.query(getIncompleteProducts); const a = await this.ds.query(getIncompleteProducts); if (a.success) { const _z = a.data[0]?.id; } return a; }; searchKysely = async (): AsyncQueryResult<Product[]> => { const query = this.ds.kysely.selectFrom('product').select(['id', 'name']); const a = await this.ds.queryKysely(query); return a; // return await this.ds.queryKysely(query); // return this.ds.queryKysely(query); }; } const kysely = {} as unknown as Kysely<DB>; const repo = new Repo(new Datasource(kysely)); const testTypes = async () => { const result = await repo.search(); const _idOrErrMessage = result.success ? result.data[0]?.id : result.error.messsage; const result2 = await repo.searchKysely(); const _idOrErrMessage2 = result2.success ? result2.data[0]?.id : result2.error.messsage; };