skip to Main Content

I have a problem here which i believe it has 2 solutions. Here is my first implementation with function overloading:

type PostgresConnectionOptions = {
  dialect: "postgres";
  config: pg.PoolConfig;
};
type MysqlConnectionOptions = {
  dialect: "mysql";
  config: mysql.PoolOptions;
};
type SQLiteConnectionOptions = {
  dialect: "sqlite";
  config: {
    filename: string;
  };
};

async function getConnection(
  options: PostgresConnectionOptions
): Promise<{ client: pg.PoolClient; dialect: "postgres" }> {
  const client = await new pg.Pool({
    ...options.config,
  }).connect();

  return {
    dialect: "postgres",
    client,
  };
}

async function getConnection(
  options: MysqlConnectionOptions
): Promise<{ client: mysql.PoolConnection; dialect: "mysql" }> {
  const client = await mysql
    .createPool({
      ...options.config,
    })
    .getConnection();
  return {
    dialect: "mysql",
    client,
  };
}
async function getConnection(
  options: SQLiteConnectionOptions
): Promise<{ client: sqlite3.Database; dialect: "sqlite" }> {
  const client = new sqlite3.Database(options.config.filename);
  return {
    client,
    dialect: "sqlite",
  };
}
async function getConnection(...args: any[]): Promise<any> {
  return {} as any;
}

The error i’m getting reads:

🌋 ‘getConnection’ is declared but its value is never read.ts(6133); Duplicate function implementation.ts(2393)

Which does’t make sense in this case because typescript should know that getConnection parameters doesn’t have the same datatype.

Getting out of of function overloading i created a function called getConnection

type ConnectionOptions =
  | PostgresConnectionOptions
  | MysqlConnectionOptions
  | SQLiteConnectionOptions;

type ConnectionResult =
  | { client: mysql.PoolConnection; dialect: "mysql" }
  | { client: pg.PoolClient; dialect: "postgres" }
  | { client: sqlite3.Database; dialect: "sqlite" };
export const getConnection = async (
  options: ConnectionOptions
): Promise<ConnectionResult> => {
  if (options.dialect === "mysql") {
const client = await mysql
  .createPool({
    ...options.config,
  })
  .getConnection();
    return { client, dialect: options.dialect } as const;
  } else if (options.dialect === "postgres") {
    const client = await new pg.Pool({
      ...options.config,
    }).connect();

    return { client, dialect: options.dialect } as const;
  } else if (options.dialect === "sqlite") {
  }
const client = new sqlite3.Database(options.config.filename);
return { client, dialect: options.dialect } as const;
};

When i call getConnection it is returning client is a union of PoolConnection | PoolClient | Database how can i make it infer the correct type based on the arguments passed. If this can be possible then the function overloading can be out, because the idea here is to get the actual return type of getConnection

2

Answers


  1. Chosen as BEST ANSWER

    Based on @BadPiggie's answer i was able to get what i wanted. Here is the final code:

    type PostgresConnectionOptions = {
      dialect: "postgres";
      config: pg.PoolConfig;
    };
    type MysqlConnectionOptions = {
      dialect: "mysql";
      config: mysql.PoolOptions;
    };
    type SQLiteConnectionOptions = {
      dialect: "sqlite";
      config: {
        filename: string;
      };
    };
    type ConnectionOptions =
      | PostgresConnectionOptions
      | MysqlConnectionOptions
      | SQLiteConnectionOptions;
    
    type ConnectionResult =
      | { client: mysql.PoolConnection; dialect: "mysql" }
      | { client: pg.PoolClient; dialect: "postgres" }
      | { client: sqlite3.Database; dialect: "sqlite" };
    
    export async function getConnection(
      options: PostgresConnectionOptions
    ): Promise<{ client: pg.PoolClient; dialect: "postgres" }>;
    
    export async function getConnection(
      options: MysqlConnectionOptions
    ): Promise<{ client: mysql.PoolConnection; dialect: "mysql" }>;
    
    export async function getConnection(
      options: SQLiteConnectionOptions
    ): Promise<{ client: sqlite3.Database; dialect: "sqlite" }>;
    
    export async function getConnection(
      options: ConnectionOptions
    ): Promise<ConnectionResult> {
      if (options.dialect === "mysql") {
        const client = await mysql
          .createPool({
            ...options.config,
          })
          .getConnection();
        return { client, dialect: options.dialect };
      } else if (options.dialect === "postgres") {
        const client = await new pg.Pool({
          ...options.config,
        }).connect();
    
        return { client, dialect: options.dialect };
      }
      const client = new sqlite3.Database(options.config.filename);
      return { client, dialect: options.dialect };
    }
    

    Now typescript is happy is i do this:

    import { getConnection } from "./src";
    (async () => {
      const { client, dialect } = await getConnection({
        config: {},
        dialect: "mysql",
      });
    })();
    

    client is typed correctly as i was expecting.


  2. You should not implement all the function declarations. You only have to implement a single function that should handle all overloadings.

    Documentation: https://www.tutorialsteacher.com/typescript/function-overloading

    type PostgresConnectionOptions = {
      dialect: "postgres";
      config: pg.PoolConfig;
    };
    type MysqlConnectionOptions = {
      dialect: "mysql";
      config: mysql.PoolOptions;
    };
    type SQLiteConnectionOptions = {
      dialect: "sqlite";
      config: {
        filename: string;
      };
    };
    
    async function getConnection(
      options: PostgresConnectionOptions
    ): Promise<{ client: pg.PoolClient; dialect: "postgres" }>;
    
    async function getConnection(
      options: MysqlConnectionOptions
    ): Promise<{ client: mysql.PoolConnection; dialect: "mysql" }>;
    
    async function getConnection(
      options: SQLiteConnectionOptions
    ): Promise<{ client: sqlite3.Database; dialect: "sqlite" }>;
    
    // You may need to use union type instead of <any>
    async function getConnection(options: PostgresConnectionOptions|MysqlConnectionOptions|SQLiteConnectionOptions): Promise<any> {
    
       // Here only you have to implement the logic for
       // If the options is PostgresConnectionOptions
       // Or If options arg is MysqlConnectionOptions
       // Or If options arg is SQLiteConnectionOptions
    }
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search