typescript - Vad gör @inject() i beroendeinjektion med tsyringe?


Jag lär mig DI med tsyringe. Jag är också helt ny på konceptet DI.

Följande utdrag fungerar och container.resolve(Foo) instansierar beroende korrekt.

import "reflect-metadata";
import { injectable, container } from "tsyringe";

class Database {
  get() {
    return "got-stuff-from-database";
  }
}

@injectable()
class Foo {
  constructor(private database: Database) {}

  checkDb() {
    return this.database.get();
  }
}

const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());

//=> got-stuff-from-database

Detta är förståeligt. Men utdraget nedan (mest hämtat från deras readme) fungerar varken för mig eller kan jag förstå det, och jag kan heller inte förstå varför vi behöver inject när vi har ovanstående injectable-dekoration. Jag är ledsen, jag sökte online och fann att alla använder det som om alla redan vet om det.

interface Database {}

@injectable()
class Foo {
  constructor(@inject("Database") private database?: Database) {}

  checkDb() {
    return 'stuff';
  }
}

const fooInstance = container.resolve(Foo);
console.log(fooInstance.checkDb());

Svar #1

Så det viktigaste att ha i åtanke är att tsyringe är ett Typescript-bibliotek. När Typescript kompileras till Javascript finns gränssnitten i princip inte längre (som Database-gränssnittet i ditt exempel), så den DI-magi som sker med klasserna kan inte göras som vanligt. Dokumentationen förklarar det så här:

Gränssnitt har ingen typpinformation vid körning, så vi behöver dekorera dem med @inject(...) så att containern vet hur de ska lösas.

Anledningen till att det fortfarande inte fungerar för dig är eftersom du bara har berättat för DI-ramverket att det måste leta efter en instans av något registrerat under token "Database" men det finns faktiskt ingenting registrerat där. Så för att få det att fungera måste du fortfarande berätta för tsyringe att "Database" har en klass eller instans kopplad till sig på följande sätt:

container.register("Database", {
  useClass: SomeDatabaseImplementation
});

Observera att du fortfarande måste skapa nämnda implementation eftersom du inte kan instansiera gränssnitt. För en djupare förståelse skulle jag rekommendera att titta på källkoden till biblioteket, den är ganska enkel att förstå och ger dig en mycket bättre förståelse för dess inre funktioner.