This is the error that I get
./src/core/providers/todoApi/TodoApiProvider.ts 10:14 Module parse failed: Unexpected character '@' (10:14) File was processed with these loaders:
constructor(@inject(TYPES.HttpClient) | httpClient) { | this.httpClient = void 0;
TodoApiProvider.ts
class DefaultTodoApiProvider implements TodoApiProvider {
private httpClient: HttpClient;
// @inject(TYPES.HttpClient) return error
constructor(@inject(TYPES.HttpClient) httpClient: HttpClient) {
this.httpClient = Dependency.get(TYPES.HttpClient);
}
async getTodoById(id: string) {
const data = await this.httpClient.get(
`https://jsonplaceholder.typicode.com/todos/${id}`
);
return data;
}
}
decorate(injectable(), TodoApiProvider);
export default DefaultTodoApiProvider;
If I put @inject(TYPES.HttpClient) above private httpClient: HttpClient; it will get another error Cannot access 'TYPES' before initialization.
.babelrc
{
"presets": [
...,
"@babel/preset-typescript"
],
"plugins": [
...,
"babel-plugin-transform-typescript-metadata",
["@babel/plugin-proposal-decorators", { "legacy": true }],
["@babel/plugin-proposal-class-properties", { "loose": true }]
],
"env": {
"test": {
"plugins": [
"transform-require-context",
"babel-plugin-transform-typescript-metadata",
"babel-plugin-parameter-decorator"
]
}
}
}
tsconfig.js
{
"compilerOptions": {
...,
"emitDecoratorMetadata": false,
},
}
Both stage 1 and stage 2 decorator proposals do not support parameter decorators. The @babel/plugin-proposal-decorators which implements the proposals do not know how to handle parameter decorators. As a result, the error message Unexpected character '@' was produced. Only Typescript is aware of parameter decorators.
I use Next.js not CRA but I believe it is the same problem. For Next.js, I solved this problem by installing ts-loader and configuring the Next.js webpack configuration to use ts-loader before babel-loader.
The snippet below is specific to Next.js. I reference it to clarify my point.
config.module.rules.forEach((rule) => {
if (rule.test instanceof RegExp && rule.test.test(".ts")) {
if (Array.isArray(rule.use)) {
rule.use.push("ts-loader");
} else {
rule.use = [rule.use, "ts-loader"];
}
}
});
About accesing TYPES before initialization, I did not investigate why it happens since it is solved by using ts-loader as well when fixing the first issue.