Búsqueda de sitios web

node.js - Usar commander en typescript


Intento usar commander en TypeScript y me gustaría darle un tipo adecuado a mi CLI. Así que empiezo con este código:

import * as program from "commander";

const cli = program
  .version("1.0.0")
  .usage("[options]")
  .option("-d, --debug", "activate more debug messages. Can be set by env var DEBUG.", false)
  .parse(process.argv);

console.log(cli.debug)

Pero recibo este error:

example.ts(9,17): error TS2339: Property 'debug' does not exist on type 'Command'.

Así que intenté agregar una interfaz, como se documenta aquí:

import * as program from "commander";

interface InterfaceCLI extends commander.Command {
  debug?: boolean;
}

const cli: InterfaceCLI = program
  .version("1.0.0")
  .usage("[options]")
  .option("-d, --debug", "activate more debug messages. Can be set by env var DEBUG.", false)
  .parse(process.argv);

console.log(cli.debug)

y recibo este error:

example.ts(3,32): error TS2503: Cannot find namespace 'commander'.

Por lo que entiendo, cli es en realidad una clase del tipo commander.Command Así que intenté agregar una clase:

import * as program from "commander";

class Cli extends program.Command {
    public debug: boolean;
}

const cli: Cli = program
  .version("1.0.0")
  .usage("[options]")
  .option("-d, --debug", "activate more debug messages. Can be set by env var DEBUG.", false)
  .parse(process.argv);

console.log(cli.debug)

Lo cual me da este error:

example.ts(7,7): error TS2322: Type 'Command' is not assignable to type 'Cli'.
  Property 'debug' is missing in type 'Command'.

No sé cómo agregar una propiedad a la clase Command, ni en mi archivo ni en un nuevo archivo .d.ts.

Respuesta #1

Con tu primer fragmento de código y las siguientes dependencias, no obtengo un error:

"dependencies": {
    "commander": "^2.11.0"
},
"devDependencies": {
  "@types/commander": "^2.9.1",
  "typescript": "^2.4.1"
}

Typescript interpreta cli.debug como any. Supongo que las declaraciones de tipos han sido actualizadas. Así que, si estás bien con any, el problema está resuelto.

Si realmente quieres decirle a Typescript el tipo de debug, la fusión de declaraciones sería, en principio, la forma de hacerlo. Básicamente funciona así:

class C {
    public foo: number;
}

interface C {
    bar: number;
}

const c = new C();
const fooBar = c.foo + c.bar;

Sin embargo, hay un problema: program.Command no es un tipo, sino una variable. Por lo tanto, no puedes hacer esto:

interface program.Command {
    debug: boolean;
}

Y mientras puedes hacer esto:

function f1(): typeof program.Command {
    return program.Command;
}

type T = typeof program.Command;

function f2(): T {
    return program.Command;
}

Tampoco puedes hacer esto:

interface typeof program.Command {
}

Ni esto:

type T = typeof program.Command;

interface T {
}

No sé si este problema podría resolverse o no.

Respuesta #2

Creo que encontré la solución, no sé realmente si es una buena práctica, pero aun así.

import { Command } from 'commander';
const cli = new Command();

interface InterfaceCLI{
  debug?: boolean;
}

cli
  .version("1.0.0")
  .usage("[options]")
  .option("-d, --debug", "activate more debug messages. Can be set by env var DEBUG.", false)
  .parse(process.argv);

const { debug } : InterfaceCli = <InterfaceCli><unknown>cli;
console.log(debug) // here debug is your cli.debug, I just used object destructuring

En la línea antes de la última estoy usando conversión de tipos, primero estoy convirtiendo a unknown para tipos no superpuestos, y luego, finalmente, convirtiendo a nuestra interfaz - InterfaceCli.

Artículos relacionados