Description
In v3.4.8, commit 36a53f6 changed TransactionSql from:
interface TransactionSql<TTypes extends Record<string, unknown> = {}> extends Sql<TTypes> {
to:
interface TransactionSql<TTypes extends Record<string, unknown> = {}> extends Omit<Sql<TTypes>,
'parameters' | 'largeObject' | 'subscribe' | 'CLOSE' | 'END' |
'PostgresError' | 'options' | 'reserve' | 'listen' | 'begin' | 'close' | 'end'
> {
The intent is correct (preventing use of tx.begin(), tx.listen() etc. which don't work inside transactions), but Omit in TypeScript creates a mapped type that only preserves named properties. It silently drops call signatures, so TransactionSql is no longer callable as a tagged template literal.
Reproduction
import postgres from "postgres";
const sql = postgres("...");
// Works fine
await sql`SELECT 1`;
// TS error: "This expression is not callable. Type 'TransactionSql<{}>' has no call signatures."
await sql.begin(async (tx) => {
await tx`SELECT 1`;
});
Suggested fix
Replace Omit with a hand-written interface that explicitly re-declares the two call signatures from Sql:
interface TransactionSql<TTypes extends Record<string, unknown> = {}> {
// Re-declare call signatures (Omit strips these)
<T, K extends Rest<T>>(first: T & First<T, K, TTypes[keyof TTypes]>, ...rest: K): Return<T, K>;
<T extends readonly (object | undefined)[] = Row[]>(
template: TemplateStringsArray,
...parameters: readonly (ParameterOrFragment<TTypes[keyof TTypes]>)[]
): PendingQuery<T>;
// Pick only the methods that are valid inside a transaction
unsafe: Sql<TTypes>['unsafe'];
typed: Sql<TTypes>['typed'];
types: Sql<TTypes>['types'];
notify: Sql<TTypes>['notify'];
array: Sql<TTypes>['array'];
file: Sql<TTypes>['file'];
json: Sql<TTypes>['json'];
savepoint<T>(cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
savepoint<T>(name: string, cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
prepare<T>(name: string): Promise<UnwrapPromiseArray<T>>;
}
This achieves the same goal (no begin, listen, subscribe, etc. on tx) without losing the call signatures.
Description
In v3.4.8, commit 36a53f6 changed
TransactionSqlfrom:to:
The intent is correct (preventing use of
tx.begin(),tx.listen()etc. which don't work inside transactions), butOmitin TypeScript creates a mapped type that only preserves named properties. It silently drops call signatures, soTransactionSqlis no longer callable as a tagged template literal.Reproduction
Suggested fix
Replace
Omitwith a hand-written interface that explicitly re-declares the two call signatures fromSql:This achieves the same goal (no
begin,listen,subscribe, etc. ontx) without losing the call signatures.