56

I'm trying out Inversify.js for a Typescript application I'm using. Right now, there is no framework involved, so it's pure ES2015.

I'm trying to follow along the example in the main page, but I'm being hit with: "Reflect.hasOwnMetadata is not a function" when I try to run it in the browser.

I'm using Webpack as package bundler.

Here is my folder structure:

enter image description here

Here is the main app.ts file:

/// <reference path="../typings/index.d.ts" />
/// <reference path="./domain/abstract/match.interface.ts" />

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

import {symbols} from "../inversify/symbols.ts";

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

ninja.fight();
ninja.sneak();

interfaces.d.ts:

interface INinja {
    fight(): string;
    sneak(): string;
}

interface IKatana {
    hit(): string;
}

interface IShuriken {
    throw();
}

inversify.config.ts

/// <reference path="../node_modules/inversify/type_definitions/inversify/inversify.d.ts" />
/// <reference path="../node_modules/reflect-metadata/reflect-metadata.d.ts" />
/// <reference path="inversify.ts" />

import {Kernel} from "inversify"
//import {MatchHub} from "../app/components/Hubs/match/match-hub.component.ts";
//import {symbols} from "./symbols.ts";


import {Ninja, Katana, Shuriken} from "./inversify.ts";


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;

symbols.ts:

export const symbols = {
    Match : Symbol("Match")
}

tsconfig.json:

{
  "compilerOptions": {
    "noImplicitAny": false,
    "experimentalDecorators": true,
    "emitDecoratorMetadata":  true, 
    "removeComments": true,
    "sourceMap": true,
    "target": "es5"
  },
  "exclude": [
    "node_modules",
    "bower_components",
    "wwwroot"
  ]
}

Webpack.config.js:

module.exports = {
  entry: './app/app.ts',
  output: {
    filename: '../Scripts/app/app.js'
  },
  resolve: {
      extensions: ['', '.Webpack.js', '.web.js', '.ts','.js', '.tsx']
  },
  module: {
    loaders: [
        {
          test: /\.ts?$/,
          exclude: /(node_modules|bower_components)/,
          loader: 'ts-loader'
        }
    ]
  },
  watch: true
}

Firefox Console Error:

firefox console error

Webpack output:

enter image description here

When I tried to install Inversify the following warnings popped up:

enter image description here

Is it a bug? Or am I doing something wrong? Thanks!

PS: Tried following the sample files, but I couldn't understand anything!

I come from ASP.NET MVC 5 with Ninject so I can relate for most of the syntax.

halfer
  • 19,824
  • 17
  • 99
  • 186
Jose A
  • 10,053
  • 11
  • 75
  • 108

2 Answers2

112

It seems you will need to include the reflect-metadata package. Try adding an import to it in inversify.config.ts by doing:

import "reflect-metadata";
David Sherret
  • 101,669
  • 28
  • 188
  • 178
  • Hi David, thanks for the answer! I used npm for installing inversify. The last picture shows the errors that npm threw at me. – Jose A May 31 '16 at 11:45
  • @JoseA oh yeah, you're right. I didn't read it closely the first time, sorry. I think you just need to import `reflect-metadata` or make sure webpack includes it (I'm not so familiar with webpack) – David Sherret May 31 '16 at 14:03
  • Thanks :D! I will try that later on. Will post back once I've tried it. Will finish something first before trying it. – Jose A May 31 '16 at 19:07
  • 4
    Hi I'm the main author of inversifyJS, importing "reflect-metadata" should solve your problem. – Remo H. Jansen May 31 '16 at 22:02
  • 10
    I would recommend placing the "reflect-metadata" import at the top (of *inversify.config.ts*). I was having this problem when importing `@injectable` classes before importing it. – Cristian Vrabie Jan 29 '17 at 19:03
  • Remo Hansen, any way a better message can be given if order of imports is not proper? – Mahesh Jun 18 '17 at 07:38
  • This solved it for me, together with the comment from @CristianVrabie. The import order is important too. – Christophe Geers Sep 05 '18 at 19:08
  • Hi @RemoH.Jansen , importing "reflect-metadata" didn't solve my issue. I'm facing the same issue in my react-native project. – Prasanth Raj May 19 '21 at 19:11
76

May be a silly thing to point out, I ran into a the same issue but it was because of the order of imports. Its unlikely to be the case for any other imports but in case of reflect-metadata it has to be imported before any classes that use it.

import { Container } from "inversify";
//reflect-metadata should be imported 
//before any interface or other imports
//also it should be imported only once
//so that a singleton is created.
import "reflect-metadata";
import Battle from "./interfaces/battle";
import EpicBattle from "./interfaces/epic_battle";
Mahesh
  • 1,583
  • 13
  • 18
  • 8
    Then call me silly. Seems kind of silly in hindsight, but it would be good if this was pointed out in the docs. – Alec Jun 17 '17 at 06:30
  • The reflect metadata import will parse the js files and actually create the container. If things are imported before the initialisation happens, it could keep a check and give a proper error. – Mahesh Jun 18 '17 at 07:37