web-dev-qa-db-fra.com

Injection de dépendance dans TypeScript

Je regarde les possibilités de faire TDD avec TypeScript . Si j'écris mes tests en TypeScript, est-il possible de faire en sorte que les instructions import renvoient des alarmes pour ma classe sous test? écrire les tests en javascript pur et s’injecter moi-même des AMD?

26
Sop Killen

J'utilise infuse.js pour Dependency Injection dans TypeScript.

Référencez les d.ts

/// <reference path="definition/infusejs/infusejs.d.ts"/>

Initialiser votre injecteur au démarrage

this.injector = new infuse.Injector();  

Dépendances de carte

this.injector.mapClass( 'TodoController', TodoController );
this.injector.mapClass( 'TodoView', TodoView );
this.injector.mapClass( 'TodoModel', TodoModel, true );  // 'true' Map as singleton

Injecter des dépendances

export class TodoController
{
    static inject = ['TodoView', 'TodoModel'];

    constructor( todoView:TodoView, todoModel:TodoModel )
    {

    }
 }

Il s'agit d'une chaîne basée sur le type (car la réflexion n'est pas encore possible dans TypeScript). Malgré cela, cela fonctionne très bien dans mes applications.

20
Philip Bulley

J'ai développé un conteneur IoC appelé InversifyJS avec des fonctionnalités avancées d'injection de dépendance, telles que les liaisons contextuelles.

Vous devez suivre 3 étapes de base pour l'utiliser:

1. Ajouter des annotations

L'API d'annotation est basée sur Angular 2.0:

import { injectable, inject } from "inversify";

@injectable()
class Katana implements IKatana {
    public hit() {
        return "cut!";
    }
}

@injectable()
class Shuriken implements IShuriken {
    public throw() {
        return "hit!";
    }
}

@injectable()
class Ninja implements INinja {

    private _katana: IKatana;
    private _shuriken: IShuriken;

    public constructor(
        @inject("IKatana") katana: IKatana,
        @inject("IShuriken") shuriken: IShuriken
    ) {
        this._katana = katana;
        this._shuriken = shuriken;
    }

    public fight() { return this._katana.hit(); };
    public sneak() { return this._shuriken.throw(); };

}

2. Déclarez les reliures

L'API de liaison est basée sur Ninject:

import { Kernel } from "inversify";

import { Ninja } from "./entities/ninja";
import { Katana } from "./entities/katana";
import { Shuriken} from "./entities/shuriken";

var kernel = new Kernel();
kernel.bind<INinja>("INinja").to(Ninja);
kernel.bind<IKatana>("IKatana").to(Katana);
kernel.bind<IShuriken>("IShuriken").to(Shuriken);

export default kernel;

3. Résoudre les dépendances

L'API de résolution est basée sur Ninject:

import kernel = from "./inversify.config";

var ninja = kernel.get<INinja>("INinja");

expect(ninja.fight()).eql("cut!"); // true
expect(ninja.sneak()).eql("hit!"); // true

La dernière version (2.0.0) prend en charge de nombreux cas d'utilisation:

  • Modules du noyau
  • Middleware du noyau
  • Utiliser des classes, des littéraux de chaîne ou des symboles comme identificateurs de dépendance
  • Injection de valeurs constantes
  • Injection de constructeurs de classe
  • Injection d'usines
  • Usine automatique
  • Injection de fournisseurs (async factory)
  • Gestionnaires d'activation (utilisés pour injecter des proxies)
  • Multi injections
  • Liaisons étiquetées
  • Décorateurs de tags personnalisés
  • Liaisons nommées
  • Liaisons contextuelles
  • Exceptions amicales (par exemple, dépendances circulaires)

Vous pouvez en apprendre plus à ce sujet sur https://github.com/inversify/InversifyJS

17
Remo H. Jansen

Essayez ceci Dependency Injector (Typejector)

GitHub Typejector

Avec le nouveau TypeScript 1.5, il est possible d’utiliser des annotations

Par exemple

    @injection
    class SingletonClass {
        public cat: string = "Kitty";
        public dog: string = "Hot";

        public say() {
            alert(`${this.cat}-Cat and ${this.dog}-Dog`);
        }
    }
    @injection
    class SimpleClass {
        public say(something: string) {
            alert(`You said ${something}?`);
        }
    }

    @resolve
    class NeedInjectionsClass {
        @inject(SingletonClass)
        public helper: SingletonClass;
        @inject(SimpleClass)
        public simpleHelper: SimpleClass;

        constructor() {
            this.helper.say();
            this.simpleHelper.say("wow");
        }
    }
    class ChildClass extends NeedInjectionsClass {

    }

    var needInjection = new ChildClass();

Pour le cas question: Une propriété devrait réaliser une pseudo interface (ou classe abstraite) comme dans l'exemple suivant.

    class InterfaceClass {
        public cat: string;
        public dog: string;

        public say() {

        }
    }

    @injection(true, InterfaceClass)
    class SingletonClass extends InterfaceClass {
        public cat: string = "Kitty";
        public dog: string = "Hot";

        public say() {
            alert(`${this.cat}-Cat and ${this.dog}-Dog`);
        }
    }

    @injection(true, InterfaceClass)
    class MockInterfaceClass extends InterfaceClass {
        public cat: string = "Kitty";
        public dog: string = "Hot";

        public say() {
            alert(`Mock-${this.cat}-Cat and Mock-${this.dog}-Dog`);
        }
    }

    @injection
    class SimpleClass {
        public say(something: string) {
            alert(`You said ${something}?`);
        }
    }

    @resolve
    class NeedInjectionsClass {
        @inject(InterfaceClass)
        public helper: InterfaceClass;
        @inject(SimpleClass)
        public simpleHelper: SimpleClass;

        constructor() {
            this.helper.say();
            this.simpleHelper.say("wow");
        }
    }

    class ChildClass extends NeedInjectionsClass {

    }

    var needInjection = new ChildClass();

Note: _ ​​L'injection simulée devrait définir après le code source car elle redéfinit le créateur de classe pour l'interface

6
Oleh Dokuka

Pour les personnes utilisant Angular2, j'ai développé Fluency Injection https://www.npmjs.com/package/fluency-injection . La documentation est assez complète et imite le comportement du DI de Angular2.

Les commentaires sont très appréciés et j'espère que cela vous aidera :)

2
Connor Wyatt

Vous pouvez essayer ceci: https://www.npmjs.com/package/easy-injectionjs . C'est un package d'injection de dépendance d'usage générique.

@EasySingleton crée une instance unique de la dépendance dans toute l'application. C'est idéal pour un service quelconque.

@EasyPrototype crée autant d'instances de la dépendance que nécessaire. C'est idéal pour les dépendances changeantes.

@EasyFactory est principalement utilisé pour l'héritage:

Vous pouvez faire n'importe quoi en utilisant ce paquet: Utilisation simple

import { Easy, EasyFactory, EasyPrototype, EasySingleton } from 'easy-injectionjs';

@EasyFactory()
abstract class Person {
  abstract getName();
  abstract setName(v: string);
}

// @EasyObservable()
@EasySingleton()
class Somebody extends Person{
  // @Easy()
  constructor (private name: string) {
    super()
    this.name = 'Sal';
  }

  public getName() {
    return this.name;
  }
  public setName(v: string) {
    this.name = v;
  }
}

@EasyPrototype()
class Nobody extends Person{
  @Easy()
  somebody: Person;
  constructor () {
    super()
  }

  public getName() {
    return this.somebody.getName();
  }

  public setName(v: string) {
    this.somebody.setName(v);
  }
}

@EasyPrototype()
class Data {
  @Easy()
  somebody: Person;
  name: string;

  change(v: string) {
    this.somebody.setName(v);
  }

  getName(): string {
    return this.somebody.getName();
  }
}

let n = new Nobody();
console.log(n.getName()) // Prints Sal
n.setName('awesome');
console.log(n.getName())  // Prints awesome
let d = new Data()
console.log(d.getName())  // Prints awesome
d.change('Gelba')
console.log(n.getName())  // Prints Gelba
d.change('kaa')
console.log(n.getName())  // Prints Kaa

Même si vous souhaitez injecter des modules de nœud, vous pouvez le faire:

import * as IExpress from 'express';
import { Easy, EasySingleton } from 'easy-injectionjs';

@EasySingleton()
class Express extends IExpress {} 

@EasySingleton()
export class App {
  @Easy()
  private _express: Express;
}

let app = new App();
console.log(app)

Bien entendu, l'utilisation du serveur express ne sert pas à la journalisation de la console. C'est juste pour tester: D.

J'espère que ça aide: D

0
Saleh Shehata

TypeScript fonctionne bien avec les chargeurs AMD tels que requirejs. S'il est configuré correctement, TypeScript générera un javascript conforme à AMD. 

Dans une situation de test, vous pouvez configurer requirejs pour injecter des modules testables. 

0
Alex Dresko