Búsqueda de sitios web

javascript - Cómo inyectar un módulo en una clase usando Typescript y NodeJS


Estoy desarrollando en NodeJS + Typescript. Tengo experiencia en programación orientada a objetos y quiero aprovechar los módulos de NodeJS, pero me está costando combinarlos con clases que no se supone que sean módulos.

Esto es lo que estoy intentando hacer:

foo.ts (módulo)

import http = require("http")

export class Foo {
    public fooMethod() : number { ... }
}

bar.ts (no se supone que sea un módulo)

namespace Ns {
    export class Bar {
        constructor(private foo: Foo) { ... } //"Foo" is not being found by the intellisense
        public barMethod() : number { 
            return this.foo.fooMethod()
        }
    }
}

server.js (archivo de inicio de node)

var Foo = import("./foo");

var foo = new Foo();
foo.configure(...)     //Configure foo before inject it into bar

var bar = new Ns.Bar(foo)

Problemas que estoy enfrentando al intentar estructurar el código de esta manera:

  1. Bar no puede ver a Foo. Intenté agregar una referencia al archivo, pero no funcionó.
  2. Funcionó cuando importé ./foo, pero cuando hago eso Bar no puede ver otros tipos exportados en otros archivos que están definidos en el mismo espacio de nombres (incluso si escribo el nombre completo del tipo, es decir, incluyo el espacio de nombres, todavía no puede verlo).
  3. Así que eliminé el espacio de nombres Ns en Bar y pude ver otros tipos cuando escribía su nombre con el espacio de nombres. Pero ahora Bar es un módulo y siento que mi inyección de constructor huele mal, ya que Foo está importado y puedo instanciarlo directamente.

No quiero imponer mis estándares. Quiero saber cuál es el enfoque correcto para lo que estoy tratando de hacer. La lucha me hace sentir que estoy obligado a rediseñar y usar módulos completos al desarrollar aplicaciones en Node.js. ¿Es eso correcto?

En caso de que deba pasar a módulos completos, ¿cómo debería gestionar la inyección de dependencias?

Gracias

Respuesta #1

Para aprovechar completamente el poder de OOP (o mejor dicho, la programación basada en interfaces o programación orientada a protocolos) deberías usar interface Foo para ocultar el uso de la implementación específica MyFoo por la clase Bar.

Foo.ts

export interface Foo {
  fooMethod(): number;
}

MiFoo.ts

export class MyFoo {
  fooMethod(): number {
    return 1;
  }
}

Bar.ts

import {Foo} from './Foo'

export class Bar {
  constructor(private foo: Foo) {}

  barMethod(): number {
    return this.foo.fooMethod();
  }
}

En algún otro lugar:

import {Boo} from './Boo'
import {MyFoo} from './MyFoo'

const result = new Boo(new MyFoo()).barMethod();

Personalmente, no recomiendo usar espacios de nombres. Puedes leer más sobre espacios de nombres y módulos aquí.