0

有一個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後創建創建我的容器,它鏈接了我所有依賴關鍵字和真實關鍵字的字符串表示,而不管它的類型如何(在這種情況下,只是symbolFunction):

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; 

任何人都知道是否有更好的方法來做到這一點,或者如果有任何重要的理由不這樣做?

+1

@ ower-reloaded也許你可以對此有所瞭解? – Danziger

回答

1

有關使用該函數的參數名稱的主要問題是潛在的問題壓縮代碼時:

function test(foo, bar) { 
    console.log(foo, bar); 
} 

變爲:

function test(a,b){console.log(a,b)} 

因爲你在一個應用程序的Node.js在工作,你可能沒有使用壓縮,所以這不應該是你的問題

我認爲你的解決方案是一個很好的時間解決方案。如果您檢查TypeScript Roapmap,「未來」一節中,我們可以看到:

  • 裝飾的函數表達式/箭頭功能

這意味着,在未來InversifyJS將允許你做到以下幾點:

注:假設AuthenticationMiddlewareUsersMiddleware

@injectable() 
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; 
} 

或執行以下操作:

注意:假設AuthenticationMiddlewareUsersMiddleware接口

@injectable() 
function getRouter(
    @inject("AuthenticationMiddleware") authenticationMiddleware: AuthenticationMiddleware, 
    @inject("UsersMiddleware") 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; 
} 
相關問題