question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Injectable decorator not recognized when used with custom decorator

See original GitHub issue

🐞 bug report

Affected Package

The issue is caused by package @angular/compiler

Is this a regression?

Yes, since everything worked fine in previous versions (Angular 8, Angular 9)

Description

In my projects I use decorators and now for some reason the error is constantly shown, what does this mean and how to get around it? Is this a bug in Angular? The decorator is ordinary and made according to the TypeScript guide

import { Component, VERSION, Injectable } from '@angular/core';

// simple example
export function Decorator(): any {
    return function <T extends any>(parent: any) {
        return class extends parent {
            constructor(...args: any[]) {
                super(...args);
            }
        };
    };
}

@Decorator()
@Injectable()
class MyService {
  public world() {
    return 'world';
  }
}

@Component({
  selector: 'my-app',
  templateUrl: './app.component.html',
  styleUrls: [ './app.component.css' ],
  providers: [MyService]
})
export class AppComponent  {
  name = 'Angular ' + VERSION.major;

  constructor(private my: MyService){
    console.log('hello', my.world())
  }
}

🔬 Minimal Reproduction

https://stackblitz.com/edit/token-invalid?file=src/app/app.component.ts

🔥 Exception or Error


DEPRECATED: DI is instantiating a token "" that inherits its @Injectable decorator but does not provide one itself.
This will become an error in a future version of Angular. Please add @Injectable() to the "" class.

🌍 Your Environment

Angular Version:

Angular 10.1

Issue Analytics

  • State:closed
  • Created 3 years ago
  • Reactions:6
  • Comments:17 (7 by maintainers)

github_iconTop GitHub Comments

2reactions
tomstolarczukcommented, Aug 13, 2021

For anybody still interested, this works:

export function Decorator(module: string): <T extends new (...args: any[]) => any>(target: T) => T {
  return function decorator<T extends new (...args: any[]) => any>(target: T): T {
    @Injectable()
    abstract class Decorated extends target {
	  someProp = 'someProp';
      // do something with decorated class
    }
    return Decorated;
  };
}


@Injectable({
  providedIn: 'root'
})
@Decorator()
export class SomeApiService {
  constructor(private http: HttpClient) {}

  someMethod(params: any): void {
    console.log(this.someProp);
  }
}

Tested on Angular 12.

1reaction
mkurciuscommented, Dec 3, 2021

As mentioned here: https://stackoverflow.com/a/53622493/4663231 Proxy and Reflect.construct can be used:

export function MyDecorator() {
  return (target: any) => {
    return new Proxy(target, {
      construct(clz, args) {
        console.log('before constructor');
        const obj = Reflect.construct(clz, args);
        console.log('after constructor');

        return obj;
      },
    });
  };
}

@MyDecorator()
@Injectable({ providedIn: 'root' })
export class MyClass {
  constructor(@Inject(DOCUMENT) private document: Document) {
    console.log('Impl (constructor)');
    console.log('document', this.document);
  }
}

@Injectable({ providedIn: 'root' })
export class MyService {
  constructor(private myClass: MyClass) {
    console.log('myClass', this.myClass);
  }
}

and the output is: result

as you can see:

  1. DI works without @Injectable inside custom decorator result -DI

  2. returned class is the original one (not wrapped) result -class

Read more comments on GitHub >

github_iconTop Results From Across the Web

Why does HTTP service require @Injectable decorator and a ...
Generally speaking, an injector reports an error when trying to instantiate a class that is not marked as @Injectable() .
Read more >
Migration for missing @Injectable() decorators and incomplete ...
This schematic adds an @Injectable() decorator to classes which are provided in the application but are not decorated. The schematic updates providers which ......
Read more >
Angular & Dependency Injection: tricks with Decorators
The SkipSelf Decorator doesn't look for the dependency in the current injector and starts from the parent injector (and then continues to go ......
Read more >
How To Use Decorators in TypeScript - DigitalOcean
The decoratorA function will be called with details about how you used the decorator in your code. For example, if you applied the...
Read more >
Decorators do not work as you might expect
While working on a library called ngx-template-streams, which in a nutshell allows you to work with e... Tagged with typescript, webdev, ...
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found