I am clearly misunderstanding how TSyringe is supposed to resolve classes with dependencies.
I created a minimal repro. In my index.tsx, I do as they indicate in the docs and import reflect-metadata
. This example works if I inject a singleton
class with no dependencies:
// index.tsx
import "reflect-metadata";
import React from 'react';
import ReactDOM from 'react-dom';
import './index.css';
import App from './App';
ReactDOM.render(<App />, document.getElementById('root'));
A single singleton class:
// _A.ts
import {inject, singleton} from 'tsyringe';
@singleton()
export class A {
get_msg() {
return "Worked!";
}
}
And the component that uses it:
// App.tsx
import React from 'react';
import './App.css';
import {container} from "tsyringe";
import {A} from "./_A";
interface Props {
a?: A
}
function App({a = container.resolve(A)}: Props) {
return (
<div className="App">
{a.get_msg()}
</div>
);
}
export default App;
When I run the app, the Worked! text is printed as expected.
However, if I create a second singleton called B:
// _B.ts
import {singleton} from 'tsyringe';
@singleton()
export class B {
get_msg() {
return "Worked!";
}
}
And then inject B
into A
to get the message:
// _A.ts
import {inject, singleton} from 'tsyringe';
import {B} from "./_B";
@singleton()
export class _A {
constructor(private b: B) {
}
get_msg() {
return this.b.get_msg();
}
}
Then it fails with Uncaught Error: TypeInfo not known for "A"
I have:
"experimentalDecorators": true,
"emitDecoratorMetadata": true,
on my tsconfig.ts
, as they indicate in the README.
Shouldn't Syringe resolve B automatically, inject B into A and then inject A into my app component so I can print the message?
What am I missing?
OK so I figured this out.
To keep the typescript metadata and allow reflect-metadata to do its thing, we need to add babel-plugin-transform-typescript-metadata
to the project.
However, in order to customize create-react-app, you need the craco
library. There are several out there, but craco is the only one I could that supports CRA 4.x. You cannot be on the latest (CRA 5.0) as none of these libs support it yet.
So:
1 - Install Craco and set it up.
2 - Install babel-plugin-transform-typescript-metadata
as a dev dependency
3 - Add a craco.config.js
file to your project to load this plugin:
module.exports = function ({ env: _env }) {
return {
babel: {
plugins: [
"babel-plugin-transform-typescript-metadata"
]
},
};
};
4 - Make sure to update your package.json to launch with craco so that the config override takes place:
"scripts": {
"start": "craco start",
"build": "craco build",
"test": "craco test",
"eject": "craco eject"
},
That's it, it will work now. Hope it helps someone out there.