Переписав Angular di.js під TypeScript-версію
На бекенді під Node.js постійно використовую Angular DI.js. Дуже зручна річ, але останнім часом на нових версіях Node.js він почав конфліктувати... то із pm2, то із node-lru-cache. І як вияснилось, конфліктує не сам Angular DI, а код після роботи транспайлера traceur.
Так і не дочекався відповіді від команди Angular, чи збираються вони продовжувати підтримувати Angular DI як окремий модуль. Придивлявся до inversify.io, але щось він здався складнішим, ніж це мені треба.
Source code Angular DI.js написано на ES2015, то ж було досить просто його підігнати під TypeScript-версію (майже не зачіпаючи початковий код). А вже TypeScript його транспайлить в робочу неконфліктну версію JavaScript.
Може кому теж цікаво спробувати — welcome!
Встановлення:
npm install ts-di --save
Використання:
import {Inject, Injector} from 'ts-di'; class A{} // All dependencies in @Inject listed separated by commas @Inject(A) class B { constructor(private a: A){} getValue() { console.log(`There should be a instance of class A:`, this.a); } } let injector = new Injector(); // Instance class B and resolve dependency let instance = injector.get(B);
Travis фейлиться (див. іконку «build failing») через... думаю через баг TypeScript, але ця помилка не впливає на роботу даного модуля.
UPD:
Зараз модуль транспільовано для ES2015. Щоб перекомпілювати його, наприклад, під ES5, то треба скачати проект із github, запустити:
npm install tsc --target es5 npm pack
Ця команда зробить архів та видасть його ім’я. Потім переходите у проект, де потрібен DI, робите
npm install /path/to/project/from-github/ts-di-1.0.11.tgz
Все, модуль готовий до використання.
P.S. Зрозуміло що номер версії може з часом змінюватись.
Оновлення від 25.01.2017
Кхм, взагалі-то мій ts-di є дуже маленьким, швидким, і зручним, але бачу що йому не вистачає того, що я спочатку забракував для себе у теперішньому Angular DI: визначення провайдерів залежностей окремим масивом.
На даний момент ts-di, наприклад при тестуванні, вміє підмінювати провайдерів залежностей наступним чином:
import { Inject ,Injector ,Provide } from 'ts-di'; class Engine {} @Inject(Engine) class Car { constructor(public engine: Engine){} start() {} } // Таким чином провайдер Engine підмінюється провайдером MockEngine @Provide(Engine) class MockEngine { start() {} } var injector = new Injector([MockEngine]); var car = injector.get(Car); /** * Expect `car` to be instance of class `Car` * and `car.engine` to be instance of class `MockEngine` */ console.log(car);
Але проблема в тому, що інколи треба підмінювати не класи, а вже готові значення, наприклад, об’єктів. На даний момент, ts-di такого не вміє робити, але це вміє робити теперішня версія Angular DI, хоча й має певні накладки:
import 'reflect-metadata'; import { Injectable ,ReflectiveInjector } from '@angular/core'; class Engine {} @Injectable() class Car { constructor(public engine: Engine){} start() {} } var injector = ReflectiveInjector.resolveAndCreate([Car, Engine]); var car = injector.get(Car); /** * Expect `car` to be instance of class `Car` * and `car.engine` to be instance of class `Engine` */ console.log(car);
Під «накладками» я маю на увазі, що для інжектора треба указувати абсолютно усіх провайдерів, навіть якщо їх є пару десятків.
Здавалося б що в даному прикладі указувати Engine другий раз буде зайвим, бо інжектор же начебто міг би й сам прочитати анотації, залишені через @Injectable(), що Car залежить від Engine, але це робиться щоб можна було підмінювати замість Engine — MockEngine
import 'reflect-metadata'; import { Injectable ,ReflectiveInjector } from '@angular/core'; class Engine {} @Injectable() class Car { constructor(public engine: Engine){} start() {} } class MockEngine { start() {} } var injector = ReflectiveInjector.resolveAndCreate([Car, {provide: Engine, useClass: MockEngine}]); var car = injector.get(Car); /** * Expect `car` to be instance of class `Car` * and `car.engine` to be instance of class `MockEngine` */ console.log(car); // Car { engine: MockEngine {} }
12 коментарів
Додати коментар Підписатись на коментаріВідписатись від коментарів