postgres icon indicating copy to clipboard operation
postgres copied to clipboard

How to use types

Open kylerush opened this issue 3 years ago • 1 comments

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);

kylerush avatar Sep 14 '22 17:09 kylerush

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

Minigugus avatar Sep 15 '22 14:09 Minigugus

Don't know if this is still relevant.. I'll close it out, as I can't help with these typescript issues.

porsager avatar Jun 25 '23 23:06 porsager