|
| 1 | +# Migration to Add Missing `@Injectable()` Decorators |
| 2 | + |
| 3 | +## What does this schematic do? |
| 4 | + |
| 5 | +This schematic adds an `@Injectable()` decorator to a class |
| 6 | +if the class has been added as a provider anywhere in the application. |
| 7 | + |
| 8 | +An example diff might look like the following: |
| 9 | + |
| 10 | +**Before:** |
| 11 | + |
| 12 | +```ts |
| 13 | +export class TypeCase {...} |
| 14 | +``` |
| 15 | + |
| 16 | +**After:** |
| 17 | + |
| 18 | +```ts |
| 19 | +@Injectable() |
| 20 | +export class TypeCase {...} |
| 21 | +``` |
| 22 | + |
| 23 | + |
| 24 | +There are a few cases where the decorator won't be added. For example: |
| 25 | + |
| 26 | + - It already has another decorator such as `@Component()`, `@Directive()` or `@Pipe()`. These decorators already cause the compiler to generate the necessary information. |
| 27 | + - The provider definition has `useValue`, `useFactory`, or `useExisting`. In |
| 28 | + these cases, the framework doesn't need the `@Injectable()` decorator to create the class because |
| 29 | + because it can just use the value, |
| 30 | + factory function, or existing instance that was provided. |
| 31 | + |
| 32 | + For example, for the following module definition, the schematic will check |
| 33 | + `TypeCase`, `ProvideCase`, `ExistingClass`, and `SomeClass` to ensure they |
| 34 | + are marked with the `@Injectable()` decorator and add one if not. |
| 35 | + |
| 36 | + |
| 37 | + ```ts |
| 38 | + @NgModule({ |
| 39 | + providers: [ |
| 40 | + // TypeCase needs @Injectable() |
| 41 | + TypeCase, |
| 42 | + // ProvideCase needs @Injectable() |
| 43 | + {provide: ProvideCase}, |
| 44 | + // No @Injectable() needed because the value will be used |
| 45 | + {provide: ValueCase, useValue: 0}, |
| 46 | + // No @Injectable() needed because factory will be used |
| 47 | + {provide: FactoryCase, useFactory: ()=> null}, |
| 48 | + // ExistingClass needs @Injectable() |
| 49 | + {provide: ExistingToken, useExisting: ExistingClass}, |
| 50 | + // SomeClass needs @Injectable() |
| 51 | + {provide: ClassToken, useClass: SomeClass}, |
| 52 | + // No @Injectable() needed because it has a @Pipe() decorator |
| 53 | + PipeCase, |
| 54 | + |
| 55 | + ] |
| 56 | + }) |
| 57 | + |
| 58 | + ``` |
| 59 | + |
| 60 | + |
| 61 | +## Why is this migration necessary? |
| 62 | + |
| 63 | +In our docs, we've always recommended adding `@Injectable()` |
| 64 | +decorators to any class that is provided or injected in your application. |
| 65 | +However, older versions of Angular did allow injection of a class |
| 66 | +without the decorator in certain cases, such as AOT mode. |
| 67 | +This means if you accidentally omitted the decorator, your application |
| 68 | +may have continued to work despite missing `@Injectable()` decorators in some places. |
| 69 | +This is problematic for future versions of Angular. Eventually, we plan |
| 70 | +to strictly require the decorator because doing so enables further |
| 71 | +optimization of both the compiler and the runtime. This schematic |
| 72 | +adds any `@Injectable()` decorators that may be missing to future-proof your app. |
| 73 | + |
| 74 | + |
| 75 | + |
| 76 | +## When should I be adding `@Injectable()` decorators to classes? |
| 77 | + |
| 78 | +Any class that is provided or injected somewhere must have an `@Injectable()` decorator. The decorator is necessary for the framework to properly create an instance of that class through DI. |
| 79 | + |
| 80 | +However, as noted above, classes that already have another class decorator like `@Pipe` do not need both decorators. The existing class decorator will cause the compiler to generate the proper information. |
| 81 | + |
| 82 | + |
| 83 | +## Should I update my library? |
| 84 | + |
| 85 | +Yes, if your library has any tokens that are meant to be injected, they should be updated with the `@Injectable()` decorator. In a future version of Angular, a missing `@Injectable()` decorator will always throw an error. |
| 86 | + |
0 commit comments