1

I'm trying to create an asynchronous version of readline with promisify.

Something to use this way:

import { Cli } from '../services/Cli';

const cli = new Cli();

const main = async () => {
  await cli.question('What is your name ? ');
  await console.log('\nBYE');

  await process.exit(0);
};

This is my attempt:

import { promisify } from 'util';
import readline from 'readline';

export class Cli {
  private cli;

  constructor() {
    this.cli = readline.createInterface({
      input: process.stdin,
      output: process.stdout,
    });
  }

  question(text: string) {
    return promisify(this.cli.question).call(this.cli, text);
  }
}

I was inspired by other wrapper I have for mysql, which is working nicely:

import { promisify } from 'util';
import mysql from 'mysql';
import config from '../../config.test.json';

export class MySQL {
  private mySQL;

  constructor() {

    this.mySQL = mysql.createConnection(config.database);
  }

  query(sql: string, args?: string | number | [] | {}) {
    return promisify(this.mySQL.query).call(this.mySQL, sql, args);
  }
}

// use it
this.mySQL = new MySQL();
const users = await this.mySQL.query("SELECT * FROM user");
return users

But is not returning anything. Any idea?

Emille C.
  • 562
  • 1
  • 7
  • 23

1 Answers1

3

The issue is caused by the interface of readline.question() function:

The callback function passed to rl.question() does not follow the typical pattern of accepting an Error object or null as the first argument. The callback is called with the provided answer as the only argument.

Promisify works only with standard callback interface:

akes a function following the common error-first callback style, i.e. taking a (err, value) => ... callback as the last argument, and returns a version that returns promises.

You need to wrap it:

  question (text) {
    return new Promise(resolve => {
      this.cli.question(text, resolve)
    })
  }

and then

    const name = await cli.question('What is your name ? ')
    console.log(name)
Manuel Spigolon
  • 11,003
  • 5
  • 50
  • 73
  • Hm, interesting… thans, I was very confused! – Emille C. Jun 05 '20 at 10:48
  • It does actually work with promisify because of this rather cryptic customization: https://github.com/nodejs/node/blob/30187baf2042dee683c5cc759e7ffad7c5a92169/lib/readline.js#L457 It's particularly confusing because the TypeScript types for it have no representation of this, so it works but doesn't compile. The node 16 docs have an example with it: https://nodejs.org/docs/latest-v16.x/api/readline.html#rlquestionquery-options-callback – Eric Haynes Aug 31 '22 at 16:56