inversify / InversifyJS

A powerful and lightweight inversion of control container for JavaScript & Node.js apps powered by TypeScript.
http://inversify.io/
MIT License
11.3k stars 717 forks source link

[Question] importing "reflect-metadata" in an "index.ts" file vs ts-config types? #1288

Open kevin-mitchell opened 3 years ago

kevin-mitchell commented 3 years ago

Hello!

I'm working on a basic TypeScript project with a really basic router library. It doesn't really matter but this is for Cloudflare Workers.

A few times in the past I've run into problems where I am able to use the DIContainer directly to get dependencies in my code, but the dependency injection annotations e.g. @Inject(TYPES.Example) do not work - specifically they return undefined.

I have read a bit and understand that under the hood the reflect-metadata is intended to be a singleton, one version of this through the entire "app". I've read many posts / questions where it turns out people are including this more than once, and so (in my mind, I'm sure it's more complicated) the object with your dependencies are flushed and you end up not having any reference to objects/constructors/factories/etc you can inject.

What I'm a bit confused by (not being a node, typescript, or webpack expert by any means!) is exactly where in my specific situation I should be including reflect-metadata. I am using a index.ts entry point, and currently it looks like this:

import "reflect-metadata";
import { DIContainer } from '../inversify.config';
import { Router } from "cloudflare-router";
import OrderHandler from "./handlers/order/order-handler";
import { TYPES } from "./di/types";;

const router = new Router();
const apiRouter = new Router();

// Connecting routers
router.use("/api", apiRouter);

// Setting up paths
router.get("/", new OrderHandler().handle);

addEventListener("fetch", event => {    
    event.respondWith(
        router.serve(event.request)
            .then(res => res.response) as Promise<Response>
    );
});

In my DIContainer, e.g. my container configuration, I do NOT import "reflect-metadata" (but of course I make sure to do so first in my index.ts entry point here).

I ALSO have a tsconfig.json file, which has reflect-metadata as a compiler option in the types object:

{
  "compilerOptions": {
    "outDir": "./dist",
    "module": "commonjs",
    "target": "esnext",
    "lib": ["esnext", "webworker", "es6"],
    "alwaysStrict": true,
    "strict": true,
    "preserveConstEnums": true,
    "moduleResolution": "node",
    "sourceMap": true,
    "esModuleInterop": true,
    "types": ["@cloudflare/workers-types", "node", "reflect-metadata"],
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
  },
  "include": [
    "./src/*.ts",
    "./test/*.ts",
    "./src/**/*.ts",
    "./test/**/*.ts",
    "./node_modules/@cloudflare/workers-types/index.d.ts"
  ],
  "exclude": ["node_modules/", "dist/"]
}

So concretely, I guess my questions are:

  1. does the inclusion of the "types" value in tsconfig negate my need to have an inclusion anywhere else?
  2. Is the fact that my index.ts entry point into my "app" is not an actual class and just "simple' javascript make a difference?

Thank you!

dcavanagh commented 3 years ago

Have you tried importing it at in your DIContainer config file? I am not sure if that will help.