有一個official recipe使用InversifyJS注入函數。基本上,我們定義了一個輔助函數會返回一個給定函數func
的咖喱版本的所有依賴使用container.get(...)
解決:使用InversifyJS注入函數的最佳方法
import { container } from "./inversify.config"
function bindDependencies(func, dependencies) {
let injections = dependencies.map((dependency) => {
return container.get(dependency);
});
return func.bind(func, ...injections);
}
export { bindDependencies };
而且我們使用這樣的:
import { bindDependencies } from "./utils/bindDependencies";
import { TYPES } from "./constants/types";
function testFunc(something, somethingElse) {
console.log(`Injected! ${something}`);
console.log(`Injected! ${somethingElse}`);
}
testFunc = bindDependencies(testFunc, [TYPES.something, TYPES.somethingElse]);
export { testFunc };
我會喜歡自動注入函數,而不是明確地提供它的依賴關係到bindDependencies
,可能是基於函數的參數名稱。事情是這樣的:
import { default as express, Router } from 'express';
import { bindDependencies } from '../injector/injector.utils';
import { AuthenticationMiddleware } from './authentication/authentication.middleware';
import { UsersMiddleware } from './users/users.middleware';
import { ENDPOINTS } from '../../../../common/endpoints/endpoints.constants';
function getRouter(
authenticationMiddleware: AuthenticationMiddleware,
usersMiddleware: UsersMiddleware,
): express.Router {
const router: express.Router = Router();
const requireAnonymity: express.Handler = authenticationMiddleware.requireAnonymity.bind(authenticationMiddleware);
const requireAuthentication: express.Handler = authenticationMiddleware.requireAuthentication.bind(authenticationMiddleware);
router.route(ENDPOINTS.AUTHENTICATION)
.put(requireAnonymity, authenticationMiddleware.login.bind(authenticationMiddleware))
.delete(requireAuthentication, authenticationMiddleware.logout.bind(authenticationMiddleware));
router.route(ENDPOINTS.USER)
.put(requireAnonymity, usersMiddleware.register.bind(usersMiddleware))
.post(requireAuthentication, usersMiddleware.update.bind(usersMiddleware))
.delete(requireAuthentication, usersMiddleware.remove.bind(usersMiddleware));
return router;
}
const router: express.Router = invoke(getRouter);
export { router as Router };
注意,在這種情況下,我只是想調用一次注入的功能,並得到它的返回值,這就是我出口,也許有更好的方法來做到這一點沒有包裹代碼在一個函數中,但我雖然直接在我的作文之外使用container.get(...)
根不是一個好主意,因爲這個模塊的依賴關係不是很清楚,並且可能遍佈所有行。另外,導出該函數將簡化測試。
要回到我的問題,我的invoke
功能如下:
function invoke<T>(fn: Function): T {
const paramNames: string[] = getParamNames(fn);
return fn.apply(null, paramNames.map((paramName: string)
=> container.get((<any>container).map[paramName.toUpperCase()]))) as T;
}
對於getParamNames
我用的是解決方案之一這裏提出:How to get function parameter names/values dynamically from javascript
(<any>container).map
是一個對象,我在inversify.config.ts
後創建創建我的容器,它鏈接了我所有依賴關鍵字和真實關鍵字的字符串表示,而不管它的類型如何(在這種情況下,只是symbol
或Function
):
const container: Container = new Container();
container.bind<FooClass>(FooClass).toSelf();
...
const map: ObjectOf<any> = {};
(<any>container)._bindingDictionary._map
.forEach((value: any, key: Function | symbol) => {
map[(typeof key === 'symbol'
? Symbol.keyFor(key) : key.name).toUpperCase()] = key;
});
(<any>container).map = map;
任何人都知道是否有更好的方法來做到這一點,或者如果有任何重要的理由不這樣做?
@ ower-reloaded也許你可以對此有所瞭解? – Danziger