Skip to content

Commit 1e6d312

Browse files
authored
Upgrade/fix types (#357)
* Add `sql.typed()` types * Fix readonly arrays in type * Allow undefined rows in types * Add verify-full to types
1 parent 9bfa902 commit 1e6d312

File tree

1 file changed

+40
-37
lines changed

1 file changed

+40
-37
lines changed

types/index.d.ts

Lines changed: 40 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -5,19 +5,25 @@ import { Readable, Writable } from 'node:stream'
55
* @param options Connection options - default to the same as psql
66
* @returns An utility function to make queries to the server
77
*/
8-
declare function postgres<T extends JSToPostgresTypeMap>(options?: postgres.Options<T>): postgres.Sql<JSToPostgresTypeMap extends T ? {} : T>
8+
declare function postgres<T extends PostgresTypeList>(options?: postgres.Options<T>): postgres.Sql<PostgresTypeList extends T ? {} : { [type in keyof T]: T[type] extends {
9+
serialize: (value: infer R) => any,
10+
parse: (raw: any) => infer R
11+
} ? R : never }>
912
/**
1013
* Establish a connection to a PostgreSQL server.
1114
* @param url Connection string used for authentication
1215
* @param options Connection options - default to the same as psql
1316
* @returns An utility function to make queries to the server
1417
*/
15-
declare function postgres<T extends JSToPostgresTypeMap>(url: string, options?: postgres.Options<T>): postgres.Sql<JSToPostgresTypeMap extends T ? {} : T>
18+
declare function postgres<T extends PostgresTypeList>(url: string, options?: postgres.Options<T>): postgres.Sql<PostgresTypeList extends T ? {} : { [type in keyof T]: T[type] extends {
19+
serialize: (value: infer R) => any,
20+
parse: (raw: any) => infer R
21+
} ? R : never }>
1622

1723
/**
1824
* Connection options of Postgres.
1925
*/
20-
interface BaseOptions<T extends JSToPostgresTypeMap> {
26+
interface BaseOptions<T extends PostgresTypeList> {
2127
/** Postgres ip address[s] or domain name[s] */
2228
host: string | string[];
2329
/** Postgres server[s] port[s] */
@@ -35,10 +41,10 @@ interface BaseOptions<T extends JSToPostgresTypeMap> {
3541
*/
3642
user: string;
3743
/**
38-
* true, prefer, require or tls.connect options
44+
* How to deal with ssl (can be a tls.connect option object)
3945
* @default false
4046
*/
41-
ssl: 'require' | 'allow' | 'prefer' | boolean | object;
47+
ssl: 'require' | 'allow' | 'prefer' | 'verify-full' | boolean | object;
4248
/**
4349
* Max number of connections
4450
* @default 10
@@ -54,8 +60,8 @@ interface BaseOptions<T extends JSToPostgresTypeMap> {
5460
* @default process.env['PGCONNECT_TIMEOUT']
5561
*/
5662
connect_timeout: number;
57-
/** Array of custom types; see more below */
58-
types: PostgresTypeList<T>;
63+
/** Array of custom types; see more in the README */
64+
types: T;
5965
/**
6066
* Enables prepare mode.
6167
* @default true
@@ -117,11 +123,9 @@ interface BaseOptions<T extends JSToPostgresTypeMap> {
117123
keep_alive: number | null;
118124
}
119125

120-
type PostgresTypeList<T> = {
121-
[name in keyof T]: T[name] extends (...args: any) => postgres.SerializableParameter
122-
? postgres.PostgresType<T[name]>
123-
: postgres.PostgresType<(...args: any) => postgres.SerializableParameter>;
124-
};
126+
interface PostgresTypeList {
127+
[name: string]: postgres.PostgresType;
128+
}
125129

126130
interface JSToPostgresTypeMap {
127131
[name: string]: unknown;
@@ -155,17 +159,17 @@ type UnwrapPromiseArray<T> = T extends any[] ? {
155159

156160
type Keys = string
157161

158-
type SerializableObject<T, K extends any[]> =
162+
type SerializableObject<T, K extends readonly any[]> =
159163
number extends K['length'] ? {} :
160164
(Record<Keys & (keyof T) & (K['length'] extends 0 ? string : K[number]), postgres.SerializableParameter | postgres.JSONValue> & Record<string, any>)
161165

162-
type First<T, K extends any[]> =
166+
type First<T, K extends readonly any[]> =
163167
// Tagged template string call
164168
T extends TemplateStringsArray ? TemplateStringsArray :
165169
// Identifiers helper
166170
T extends string ? string :
167171
// Dynamic values helper (depth 2)
168-
T extends readonly any[][] ? postgres.EscapableArray[] :
172+
T extends readonly any[][] ? readonly postgres.EscapableArray[] :
169173
// Insert/update helper (depth 2)
170174
T extends readonly (object & infer R)[] ? (R extends postgres.SerializableParameter ? readonly postgres.SerializableParameter[] : readonly SerializableObject<R, K>[]) :
171175
// Dynamic values/ANY helper (depth 1)
@@ -177,14 +181,14 @@ type First<T, K extends any[]> =
177181

178182
type Rest<T> =
179183
T extends TemplateStringsArray ? never : // force fallback to the tagged template function overload
180-
T extends string ? string[] :
181-
T extends readonly any[][] ? [] :
182-
T extends readonly (object & infer R)[] ? (Keys & keyof R)[] :
183-
T extends readonly any[] ? [] :
184-
T extends object ? (Keys & keyof T)[] :
184+
T extends string ? readonly string[] :
185+
T extends readonly any[][] ? readonly [] :
186+
T extends readonly (object & infer R)[] ? readonly (Keys & keyof R)[] :
187+
T extends readonly any[] ? readonly [] :
188+
T extends object ? readonly (Keys & keyof T)[] :
185189
any
186190

187-
type Return<T, K extends any[]> =
191+
type Return<T, K extends readonly any[]> =
188192
[T] extends [TemplateStringsArray] ?
189193
[unknown] extends [T] ? postgres.Helper<T, K> : // ensure no `PendingQuery` with `any` types
190194
[TemplateStringsArray] extends [T] ? postgres.PendingQuery<postgres.Row[]> :
@@ -260,13 +264,13 @@ declare namespace postgres {
260264
*/
261265
function fromKebab(str: string): string;
262266

263-
const BigInt: PostgresType<(number: bigint) => string>;
267+
const BigInt: PostgresType<bigint>;
264268

265-
interface PostgresType<T extends (...args: any[]) => unknown> {
269+
interface PostgresType<T = any> {
266270
to: number;
267271
from: number[];
268-
serialize: T;
269-
parse: (raw: string) => unknown;
272+
serialize: (value: T) => unknown;
273+
parse: (raw: any) => T;
270274
}
271275

272276
interface ConnectionParameters {
@@ -279,7 +283,7 @@ declare namespace postgres {
279283
[name: string]: string;
280284
}
281285

282-
interface Options<T extends JSToPostgresTypeMap> extends Partial<BaseOptions<T>> {
286+
interface Options<T extends PostgresTypeList> extends Partial<BaseOptions<T>> {
283287
/** @inheritdoc */
284288
host?: string;
285289
/** @inheritdoc */
@@ -311,7 +315,7 @@ declare namespace postgres {
311315
timeout?: Options<T>['idle_timeout'];
312316
}
313317

314-
interface ParsedOptions<T extends JSToPostgresTypeMap> extends BaseOptions<T> {
318+
interface ParsedOptions<T extends JSToPostgresTypeMap> extends BaseOptions<{ [name in keyof T]: PostgresType<T[name]> }> {
315319
/** @inheritdoc */
316320
host: string[];
317321
/** @inheritdoc */
@@ -320,8 +324,8 @@ declare namespace postgres {
320324
pass: null;
321325
/** @inheritdoc */
322326
transform: Transform;
323-
serializers: Record<number, (...args: any) => SerializableParameter>;
324-
parsers: Record<number, (value: string) => unknown>;
327+
serializers: Record<number, (value: any) => unknown>;
328+
parsers: Record<number, (value: any) => unknown>;
325329
}
326330

327331
interface Transform {
@@ -471,10 +475,10 @@ declare namespace postgres {
471475
| string
472476
| number
473477
| Date // serialized as `string`
474-
| JSONValue[]
478+
| readonly JSONValue[]
475479
| { toJSON(): any } // `toJSON` called by `JSON.stringify`; not typing the return type, typings is strict enough anyway
476480
| {
477-
[prop: string | number]:
481+
readonly [prop: string | number]:
478482
| undefined
479483
| JSONValue
480484
| ((...args: any) => any) // serialized as `undefined`
@@ -568,7 +572,7 @@ declare namespace postgres {
568572
unlisten(): Promise<void>
569573
}
570574

571-
interface Helper<T, U extends any[] = T[]> extends NotAPromise {
575+
interface Helper<T, U extends readonly any[] = T[]> extends NotAPromise {
572576
first: T;
573577
rest: U;
574578
}
@@ -588,18 +592,17 @@ declare namespace postgres {
588592
* @param parameters Interpoled values of the template string
589593
* @returns A promise resolving to the result of your query
590594
*/
591-
<T extends readonly object[] = Row[]>(template: TemplateStringsArray, ...parameters: (SerializableParameter | PendingQuery<any>)[]): PendingQuery<AsRowList<T>>;
595+
<T extends readonly (object | undefined)[] = Row[]>(template: TemplateStringsArray, ...parameters: readonly (SerializableParameter | PendingQuery<any>)[]): PendingQuery<AsRowList<T>>;
592596

593597
CLOSE: {};
594598
END: this['CLOSE'];
595599
PostgresError: typeof PostgresError;
596600

597601
options: ParsedOptions<TTypes>;
598602
parameters: ConnectionParameters;
599-
types: {
600-
[name in keyof TTypes]: TTypes[name] extends (...args: any) => any
601-
? (...args: Parameters<TTypes[name]>) => postgres.Parameter<ReturnType<TTypes[name]>>
602-
: (...args: any) => postgres.Parameter<any>;
603+
types: this['typed'];
604+
typed: (<T>(value: T, oid: number) => Parameter<T>) & {
605+
[name in keyof TTypes]: (value: TTypes[name]) => postgres.Parameter<TTypes[name]>
603606
};
604607

605608
unsafe<T extends any[] = (Row & Iterable<Row>)[]>(query: string, parameters?: SerializableParameter[], queryOptions?: UnsafeQueryOptions): PendingQuery<AsRowList<T>>;

0 commit comments

Comments
 (0)