microsoft / tsyringe

Lightweight dependency injection container for JavaScript/TypeScript
MIT License
4.99k stars 167 forks source link

Uncaught TypeInfo not known for function Bar(foo) #29

Closed user753 closed 5 years ago

user753 commented 5 years ago

I created a react app with --typescript install tsyringe and reflect-metadata and got this error

Uncaught TypeInfo not known for function Bar(foo)
import {container, injectable} from "tsyringe"

export class Foo {}

@injectable()
export class Bar {
  constructor(public foo: Foo) {}
}

export const myBar = container.resolve(Bar);
Xapphire13 commented 5 years ago

Do you have the following in your tsconfig.json?

"compilerOptions": {
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true
}
user753 commented 5 years ago

@Xapphire13 Yes

{
  "compilerOptions": {
    "target": "es5",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": true,
    "experimentalDecorators": true,
    "emitDecoratorMetadata": true,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "preserve"
  },
  "include": [
    "src"
  ]
}
Xapphire13 commented 5 years ago

You have an import "reflect-metadata"; before your code executes right?

user753 commented 5 years ago

@Xapphire13 Yes, otherwize it would be tsyringe requires a reflect polyfill. Please add 'import "reflect-metadata"' to the top of your entry point.. Did you try to use tsyringe with create-react-app?

Xapphire13 commented 5 years ago

No I haven't tried that yet. The error about polyfill is relatively new and you never specified the version you're using, I just wanted to cover all bases.

Xapphire13 commented 5 years ago

I just created a react-app using create-react-app --typescript, added your sample code and got the same issue.

I then did some digging and this is because decorators are explicitly disabled for create-react-app apps.

In order to use decorators you must eject your app first.

user753 commented 5 years ago

@Xapphire13 They support decorators for typescript https://github.com/facebook/create-react-app/releases/tag/v2.1.1

function foo() {
    console.log("f(): evaluated");
    return function (target:any , propertyKey: string, descriptor: PropertyDescriptor) {
        console.log("f(): called");
    }
}

class Test {
    @foo()
    method() {}
}

new Test().method()

Works just fine.

Xapphire13 commented 5 years ago

The next thing would be the babel config that create-react-app uses, see: https://github.com/rbuckton/reflect-metadata/issues/104

For some reason all the type info is stripped. I personally use tsyringe in an ejected app with no issues (I don't use babel in my app)

user753 commented 5 years ago

Ok. I think it will be solved with this https://github.com/facebook/create-react-app/issues/6388

perf2711 commented 5 years ago

If you stumble upon this issue outside of React, be sure that the service you're resolving has a @injectable() decorator.

xenoterracide commented 4 years ago

hmmm... getting this in a jest test...

import { ApolloServerTestClient } from 'apollo-server-testing';
import 'reflect-metadata';
import testContext from '../test-fixtures/testContext';
import { Beans } from '../types/Beans';

test('version query', async() => {
  const { query } = await testContext()
    .resolve<Promise<ApolloServerTestClient>>(Beans.APOLLO_TEST_CLIENT);
  const res = await query({ query: '{ version }' });
  expect(res.data).toEqual({ version: 'dev' });
});

it's complaining at test

Error: Failed: "TypeInfo not known for function Object() { [native code] }"
Error: 
    at Env.it (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-jasmine2/build/jasmineAsyncInstall.js:91:24)
    at it (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-jasmine2/build/jasmine/jasmineLight.js:93:21)
    at Object.<anonymous> (/Users/calebcushing/IdeaProjects/service-graph/src/__tests__/VersionTest.ts:6:1)
    at Runtime._execModule (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-runtime/build/index.js:867:68)
    at Runtime._loadModule (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-runtime/build/index.js:577:12)
    at Runtime.requireModule (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-runtime/build/index.js:433:10)
    at /Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-jasmine2/build/index.js:202:13
    at Generator.next (<anonymous>)
    at asyncGeneratorStep (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-jasmine2/build/index.js:27:24)
    at _next (/Users/calebcushing/IdeaProjects/service-graph/node_modules/jest-jasmine2/build/index.js:47:9)

I'm sure I've done something wrong... but this feels like a red herring, like where is the thing that's really wrong?

xenoterracide commented 4 years ago

I ended up walking through my "resolutions" until I found the ones, failing, they needed an @inject("tag") but, this is an especially terrible exception, because it doesn't come from the attempt to resolve, and it doesn't tell me what it can't inject or what class it's trying to inject to, or even which class it's ultimately trying to resolve.

could we reopen this for better exceptions?

xenoterracide commented 4 years ago

I opened a new issue #70

Lusito commented 4 years ago

Anyone stumbling over this issue, check if you imported the class via import type. TypeScript does not catch, that the type is being used as a value here!

I had other types imported from a file when I auto-imported the class from it (which added it to the import type definition).

Maybe this specific problem could be solved with an eslint rule or something.

kmannislands commented 4 years ago

For those struggling with this error in create-react-app typescript, the issue doesn't appear to be resolved against the latest version.

As noted above, CRA supports ts decorators (test here) and emitting decorator metadata.

The issue is that babel still strips this metadata out, where babel is used in the web bundle and jest by CRA. See these issues for context: https://github.com/facebook/create-react-app/issues/6388 (doesn't appear to have solved it) https://github.com/babel/babel/issues/9681

I solved this in my case without ejecting by using craco to configure babel to use babel-plugin-transform-typescript-metadata

jonatanlins commented 2 years ago

I had this same issue with Expo, this solution worked for me: https://github.com/inversify/InversifyJS/issues/1007#issuecomment-490835213

aleksikontkanen commented 1 year ago

Had this issue on React Native. I had some decorated classes that depended on objects outside the class. Refactoring those fixed the issue.

roddc commented 1 year ago

I have this same issue with Vite3, is this library not compatible with Vite?

kmannislands commented 1 year ago

I have this same issue with Vite3, is this library not compatible with Vite?

Vite uses esbuild under the hood which doesn't emit decorator metadata.

There are a few options to work around this in practice, all involving transpiling modules with something other than esbuild like babel or swc.

In my case, I didn't want to drag in any additional dependencies so I wrote a custom vite plugin that transpiles modules that use decorators with the vanilla typescript compiler via the programmatic API.

juanvilladev commented 1 year ago

If you're running into this issue with Jest, ensure you have the following plugins:

  transform: {
    // Use babel-jest to transpile tests with the next/babel preset
    // https://jestjs.io/docs/configuration#transform-objectstring-pathtotransformer--pathtotransformer-object
    "^.+\\.(js|jsx|ts|tsx)$": [
      "babel-jest",
      {
        presets: ["next/babel"],
        plugins: [
          ["@babel/plugin-proposal-decorators", { legacy: true }], //THIS ONE
          "babel-plugin-transform-typescript-metadata", // AND THIS ONE
        ],
      },
    ],
  },