How to use types
I am attempting to create a Postgres.js plugin for Fastify. In terms of the code, everything works just fine. However, I'm struggling with finding a way to pass the type information from Postgres.js to Fastify. I'm not as good with Typescript as I'd like to be so any help would be much appreciated 🙏
I have a repo setup here.
Problem 1: Set type information for the postgres.Sql function via declaration merging
Fastify recommend to use declaration merging to set the type information for plugins--in this case I'm just decorating the Fastify instance with its .decorate function. I currently have the type set to postgres.Sql<Record<string, unknown>>, but this is incorrect as eslint tells me Unexpected await of a non-Promise (non-"Thenable") value..
Problem 2: Set the type information for the argument/options object for the postgres function
I need to find a way to tell Fastify the type for the options object that is passed to the postgres function. In the code below I created an interface that copies a lot of the type information, but I'm sure this is janky and there must be a better way.
Take a look at the index.ts file:
import type { FastifyPluginCallback } from "fastify";
import fp from "fastify-plugin";
import postgres from "postgres";
declare module "fastify" {
interface FastifyInstance {
sql: postgres.Sql<Record<string, unknown>>
}
}
export interface fastifyPostgresJsOptions {
host?: string;
port?: number;
path?: string;
database?: string;
username?: string;
password?: string;
ssl?: boolean;
max?: number;
max_lifetime?: number;
idle_tieout?: number;
connect_timeout?: number;
prepare?: boolean;
debug?: () => unknown;
connection?: {
application_name: "";
};
fetch_types?: boolean;
}
const fastifyPostgresJs: FastifyPluginCallback<fastifyPostgresJsOptions> = (
fastify,
options,
done
) => {
const sql = postgres(options);
fastify.decorate("sql", sql);
fastify.addHook("onClose", async () => {
await sql.end();
});
done();
};
export default fp(fastifyPostgresJs);
Regarding problem 1
I don't really understand why eslint complains about await when you only have 1 await on sql.end() :/ Are you sure you used the tagged template string format to issue SQL calls, and not the normal function call?
await sql(`SELECT 1`); // BAD: non-"Thenable", will throw at runtime
await sql`SELECT 1`; // OK, it's how `sql` is meant to be used
Regarding problem 2
The postgres() function's option argument is of type postgres.Option<T>, so you can just use this type instead of fastifyPostgresJsOptions:
import type { FastifyPluginCallback } from "fastify";
import fp from "fastify-plugin";
import postgres from "postgres";
declare module "fastify" {
interface FastifyInstance {
sql: postgres.Sql<Record<string, unknown>>
}
}
const fastifyPostgresJs: FastifyPluginCallback<postgres.Options<{}>> = (
fastify,
options,
done
) => {
const sql = postgres(options);
fastify.decorate("sql", sql);
fastify.addHook("onClose", async () => {
await sql.end();
});
done();
};
export default fp(fastifyPostgresJs);
The only remaining issues are Record<string, unknown> and the {} in postgres.Options<{}>, but should be fixed by #416
Don't know if this is still relevant.. I'll close it out, as I can't help with these typescript issues.