Skip to content

Commit 097d272

Browse files
authored
Fix some undefined types issues (#447)
* Support `exactOptionalPropertyTypes` - fixes #407 * Allow `undefined` properties with insert helper (types only) - fixes #446 * Allow sql fragements as tagged template parameters (types only)
1 parent 3415278 commit 097d272

File tree

2 files changed

+68
-57
lines changed

2 files changed

+68
-57
lines changed

types/index.d.ts

Lines changed: 66 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ 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 PostgresTypeList>(options?: postgres.Options<T>): postgres.Sql<PostgresTypeList extends T ? {} : { [type in keyof T]: T[type] extends {
8+
declare function postgres<T extends PostgresTypeList>(options?: postgres.Options<T> | undefined): postgres.Sql<PostgresTypeList extends T ? {} : { [type in keyof T]: T[type] extends {
99
serialize: (value: infer R) => any,
1010
parse: (raw: any) => infer R
1111
} ? R : never }>
@@ -15,7 +15,7 @@ declare function postgres<T extends PostgresTypeList>(options?: postgres.Options
1515
* @param options Connection options - default to the same as psql
1616
* @returns An utility function to make queries to the server
1717
*/
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 {
18+
declare function postgres<T extends PostgresTypeList>(url: string, options?: postgres.Options<T> | undefined): postgres.Sql<PostgresTypeList extends T ? {} : { [type in keyof T]: T[type] extends {
1919
serialize: (value: infer R) => any,
2020
parse: (raw: any) => infer R
2121
} ? R : never }>
@@ -25,9 +25,9 @@ declare function postgres<T extends PostgresTypeList>(url: string, options?: pos
2525
*/
2626
interface BaseOptions<T extends PostgresTypeList> {
2727
/** Postgres ip address[s] or domain name[s] */
28-
host: string | string[];
28+
host: string | string[] | undefined;
2929
/** Postgres server[s] port[s] */
30-
port: number | number[];
30+
port: number | number[] | undefined;
3131
/** unix socket path (usually '/tmp') */
3232
path: string | undefined;
3333
/**
@@ -84,24 +84,24 @@ interface BaseOptions<T extends PostgresTypeList> {
8484
/** Transforms incoming and outgoing column names */
8585
column?: ((column: string) => string) | {
8686
/** SQL to JS */
87-
from?: (column: string) => string;
87+
from?: ((column: string) => string) | undefined;
8888
/** JS to SQL */
89-
to?: (column: string) => string;
90-
};
89+
to?: ((column: string) => string) | undefined;
90+
} | undefined;
9191
/** Transforms incoming and outgoing row values */
9292
value?: ((value: any) => any) | {
9393
/** SQL to JS */
94-
from?: (value: unknown) => any;
94+
from?: ((value: unknown) => any) | undefined;
9595
// /** JS to SQL */
96-
// to?: (value: unknown) => any; // unused
97-
};
96+
// to?: ((value: unknown) => any) | undefined; // unused
97+
} | undefined;
9898
/** Transforms entire rows */
9999
row?: ((row: postgres.Row) => any) | {
100100
/** SQL to JS */
101-
from?: (row: postgres.Row) => any;
101+
from?: ((row: postgres.Row) => any) | undefined;
102102
// /** JS to SQL */
103-
// to?: (row: postgres.Row) => any; // unused
104-
};
103+
// to?: ((row: postgres.Row) => any) | undefined; // unused
104+
} | undefined;
105105
};
106106
/** Connection parameters */
107107
connection: Partial<postgres.ConnectionParameters>;
@@ -164,7 +164,7 @@ type Keys = string
164164

165165
type SerializableObject<T, K extends readonly any[], TT> =
166166
number extends K['length'] ? {} :
167-
(Record<Keys & (keyof T) & (K['length'] extends 0 ? string : K[number]), postgres.SerializableParameter<TT> | postgres.JSONValue> & Record<string, any>)
167+
Partial<(Record<Keys & (keyof T) & (K['length'] extends 0 ? string : K[number]), postgres.ParameterOrJSON<TT> | undefined> & Record<string, any>)>
168168

169169
type First<T, K extends readonly any[], TT> =
170170
// Tagged template string call
@@ -209,17 +209,17 @@ declare namespace postgres {
209209
line: string;
210210
routine: string;
211211

212-
detail?: string;
213-
hint?: string;
214-
internal_position?: string;
215-
internal_query?: string;
216-
where?: string;
217-
schema_name?: string;
218-
table_name?: string;
219-
column_name?: string;
220-
data?: string;
221-
type_name?: string;
222-
constraint_name?: string;
212+
detail?: string | undefined;
213+
hint?: string | undefined;
214+
internal_position?: string | undefined;
215+
internal_query?: string | undefined;
216+
where?: string | undefined;
217+
schema_name?: string | undefined;
218+
table_name?: string | undefined;
219+
column_name?: string | undefined;
220+
data?: string | undefined;
221+
type_name?: string | undefined;
222+
constraint_name?: string | undefined;
223223

224224
/** Only set when debug is enabled */
225225
query: string;
@@ -285,34 +285,34 @@ declare namespace postgres {
285285

286286
interface Options<T extends PostgresTypeList> extends Partial<BaseOptions<T>> {
287287
/** @inheritdoc */
288-
host?: string;
288+
host?: string | undefined;
289289
/** @inheritdoc */
290-
port?: number;
290+
port?: number | undefined;
291291
/** @inheritdoc */
292-
path?: string;
292+
path?: string | undefined;
293293
/** Password of database user (an alias for `password`) */
294-
pass?: Options<T>['password'];
294+
pass?: Options<T>['password'] | undefined;
295295
/**
296296
* Password of database user
297297
* @default process.env['PGPASSWORD']
298298
*/
299-
password?: string | (() => string | Promise<string>);
299+
password?: string | (() => string | Promise<string>) | undefined;
300300
/** Name of database to connect to (an alias for `database`) */
301-
db?: Options<T>['database'];
301+
db?: Options<T>['database'] | undefined;
302302
/** Username of database user (an alias for `user`) */
303-
username?: Options<T>['user'];
303+
username?: Options<T>['user'] | undefined;
304304
/** Postgres ip address or domain name (an alias for `host`) */
305-
hostname?: Options<T>['host'];
305+
hostname?: Options<T>['host'] | undefined;
306306
/**
307307
* Disable prepared mode
308308
* @deprecated use "prepare" option instead
309309
*/
310-
no_prepare?: boolean;
310+
no_prepare?: boolean | undefined;
311311
/**
312312
* Idle connection timeout in seconds
313313
* @deprecated use "idle_timeout" option instead
314314
*/
315-
timeout?: Options<T>['idle_timeout'];
315+
timeout?: Options<T>['idle_timeout'] | undefined;
316316
}
317317

318318
interface ParsedOptions<T extends JSToPostgresTypeMap> extends BaseOptions<{ [name in keyof T]: PostgresType<T[name]> }> {
@@ -380,7 +380,7 @@ declare namespace postgres {
380380
| 'CONNECTION_ENDED';
381381
errno: this['code'];
382382
address: string;
383-
port?: number;
383+
port?: number | undefined;
384384
}
385385

386386
interface NotSupportedError extends globalThis.Error {
@@ -437,21 +437,21 @@ declare namespace postgres {
437437

438438
interface LargeObject {
439439
writable(options?: {
440-
highWaterMark?: number,
441-
start?: number
442-
}): Promise<Writable>;
440+
highWaterMark?: number | undefined,
441+
start?: number | undefined
442+
} | undefined): Promise<Writable>;
443443
readable(options?: {
444-
highWaterMark?: number,
445-
start?: number,
446-
end?: number
447-
}): Promise<Readable>;
444+
highWaterMark?: number | undefined,
445+
start?: number | undefined,
446+
end?: number | undefined
447+
} | undefined): Promise<Readable>;
448448

449449
close(): Promise<void>;
450450
tell(): Promise<void>;
451451
read(size: number): Promise<void>;
452452
write(buffer: Uint8Array): Promise<[{ data: Uint8Array }]>;
453453
truncate(size: number): Promise<void>;
454-
seek(offset: number, whence?: number): Promise<void>;
454+
seek(offset: number, whence?: number | undefined): Promise<void>;
455455
size(): Promise<[{ position: bigint, size: bigint }]>;
456456
}
457457

@@ -499,7 +499,7 @@ declare namespace postgres {
499499
type: number;
500500
table: number;
501501
number: number;
502-
parser?(raw: string): unknown;
502+
parser?: ((raw: string) => unknown) | undefined;
503503
}
504504

505505
type ColumnList<T> = (T extends string ? Column<T> : never)[];
@@ -550,7 +550,7 @@ declare namespace postgres {
550550
stream(cb: (row: NonNullable<TRow[number]>, result: ExecutionResult<TRow[number]>) => void): never;
551551
forEach(cb: (row: NonNullable<TRow[number]>, result: ExecutionResult<TRow[number]>) => void): Promise<ExecutionResult<TRow[number]>>;
552552

553-
cursor(rows?: number): AsyncIterable<NonNullable<TRow[number]>[]>;
553+
cursor(rows?: number | undefined): AsyncIterable<NonNullable<TRow[number]>[]>;
554554
cursor(cb: (row: [NonNullable<TRow[number]>]) => void): Promise<ExecutionResult<TRow[number]>>;
555555
cursor(rows: number, cb: (rows: NonNullable<TRow[number]>[]) => void): Promise<ExecutionResult<TRow[number]>>;
556556
}
@@ -583,6 +583,16 @@ declare namespace postgres {
583583
rest: U;
584584
}
585585

586+
type Fragment = PendingQuery<any>
587+
588+
type ParameterOrJSON<T> =
589+
| SerializableParameter<T>
590+
| JSONValue
591+
592+
type ParameterOrFragment<T> =
593+
| SerializableParameter<T>
594+
| Fragment
595+
586596
interface Sql<TTypes extends JSToPostgresTypeMap> {
587597
/**
588598
* Query helper
@@ -598,7 +608,7 @@ declare namespace postgres {
598608
* @param parameters Interpoled values of the template string
599609
* @returns A promise resolving to the result of your query
600610
*/
601-
<T extends readonly (object | undefined)[] = Row[]>(template: TemplateStringsArray, ...parameters: readonly (SerializableParameter<TTypes[keyof TTypes]> | PendingQuery<any>)[]): PendingQuery<T>;
611+
<T extends readonly (object | undefined)[] = Row[]>(template: TemplateStringsArray, ...parameters: readonly (ParameterOrFragment<TTypes[keyof TTypes]>)[]): PendingQuery<T>;
602612

603613
CLOSE: {};
604614
END: this['CLOSE'];
@@ -611,22 +621,22 @@ declare namespace postgres {
611621
[name in keyof TTypes]: (value: TTypes[name]) => postgres.Parameter<TTypes[name]>
612622
};
613623

614-
unsafe<T extends any[] = (Row & Iterable<Row>)[]>(query: string, parameters?: SerializableParameter<TTypes[keyof TTypes]>[], queryOptions?: UnsafeQueryOptions): PendingQuery<T>;
615-
end(options?: { timeout?: number }): Promise<void>;
624+
unsafe<T extends any[] = (Row & Iterable<Row>)[]>(query: string, parameters?: (ParameterOrJSON<TTypes[keyof TTypes]>)[] | undefined, queryOptions?: UnsafeQueryOptions | undefined): PendingQuery<T>;
625+
end(options?: { timeout?: number | undefined } | undefined): Promise<void>;
616626

617-
listen(channel: string, onnotify: (value: string) => void, onlisten?: () => void): ListenRequest;
627+
listen(channel: string, onnotify: (value: string) => void, onlisten?: (() => void) | undefined): ListenRequest;
618628
notify(channel: string, payload: string): PendingRequest;
619629

620-
subscribe(event: string, cb: (row: Row | null, info: ReplicationEvent) => void, onsubscribe?: () => void): Promise<SubscriptionHandle>;
630+
subscribe(event: string, cb: (row: Row | null, info: ReplicationEvent) => void, onsubscribe?: (() => void) | undefined): Promise<SubscriptionHandle>;
621631

622-
largeObject(oid?: number, /** @default 0x00020000 | 0x00040000 */ mode?: number): Promise<LargeObject>;
632+
largeObject(oid?: number | undefined, /** @default 0x00020000 | 0x00040000 */ mode?: number | undefined): Promise<LargeObject>;
623633

624634
begin<T>(cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
625635
begin<T>(options: string, cb: (sql: TransactionSql<TTypes>) => T | Promise<T>): Promise<UnwrapPromiseArray<T>>;
626636

627-
array<T extends SerializableParameter<TTypes[keyof TTypes]>[] = SerializableParameter<TTypes[keyof TTypes]>[]>(value: T, type?: number): ArrayParameter<T>;
628-
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, options?: { cache?: boolean }): PendingQuery<T>;
629-
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, args: SerializableParameter<TTypes[keyof TTypes]>[], options?: { cache?: boolean }): PendingQuery<T>;
637+
array<T extends SerializableParameter<TTypes[keyof TTypes]>[] = SerializableParameter<TTypes[keyof TTypes]>[]>(value: T, type?: number | undefined): ArrayParameter<T>;
638+
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, options?: { cache?: boolean | undefined } | undefined): PendingQuery<T>;
639+
file<T extends readonly any[] = Row[]>(path: string | Buffer | URL | number, args: (ParameterOrJSON<TTypes[keyof TTypes]>)[], options?: { cache?: boolean | undefined } | undefined): PendingQuery<T>;
630640
json(value: JSONValue): Parameter;
631641
}
632642

@@ -635,7 +645,7 @@ declare namespace postgres {
635645
* When executes query as prepared statement.
636646
* @default false
637647
*/
638-
prepare?: boolean;
648+
prepare?: boolean | undefined;
639649
}
640650

641651
interface TransactionSql<TTypes extends JSToPostgresTypeMap> extends Sql<TTypes> {

types/tsconfig.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
],
99
"esModuleInterop": true,
1010
"strict": true,
11-
"noImplicitAny": true
11+
"noImplicitAny": true,
12+
"exactOptionalPropertyTypes": true
1213
}
1314
}

0 commit comments

Comments
 (0)