From c88305d2ebd5c8be3065dc356f7edbe4069d4ef3 Mon Sep 17 00:00:00 2001 From: Kapunahele Wong Date: Tue, 10 Sep 2019 10:55:28 -0400 Subject: [PATCH] docs: add Injectable migration docs (#32581) PR Close #32581 --- .github/CODEOWNERS | 2 + aio/content/guide/deprecations.md | 10 ++- aio/content/guide/migration-injectable.md | 86 +++++++++++++++++++++++ 3 files changed, 96 insertions(+), 2 deletions(-) create mode 100644 aio/content/guide/migration-injectable.md diff --git a/.github/CODEOWNERS b/.github/CODEOWNERS index 410656958e341..a715abda0ed0a 100644 --- a/.github/CODEOWNERS +++ b/.github/CODEOWNERS @@ -845,6 +845,8 @@ testing/** @angular/fw-test /aio/content/guide/migration-renderer.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes /aio/content/guide/migration-undecorated-classes.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes /aio/content/guide/migration-dynamic-flag.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes +/aio/content/guide/migration-injectable.md @angular/fw-docs-packaging @angular/framework-global-approvers @angular/framework-global-approvers-for-docs-only-changes + # ================================================ diff --git a/aio/content/guide/deprecations.md b/aio/content/guide/deprecations.md index d2eb11e8ea0b4..96a0e2d48dfd9 100644 --- a/aio/content/guide/deprecations.md +++ b/aio/content/guide/deprecations.md @@ -361,10 +361,16 @@ See the [dedicated migration guide for Renderer](guide/migration-renderer). {@a undecorated-classes} ### Migrating undecorated classes - See the [dedicated migration guide for undecorated classes](guide/migration-undecorated-classes). + +See the [dedicated migration guide for undecorated classes](guide/migration-undecorated-classes). + +{@a injectable} +### Adding missing `@Injectable()` decorators + +See the [dedicated migration guide for adding missing `@Injectable` decorators](guide/migration-injectable). {@a flag-migration} -### Dynamic queries flag migration +### Migrating dynamic queries See the [dedicated migration guide for dynamic queries](guide/migration-dynamic-flag). diff --git a/aio/content/guide/migration-injectable.md b/aio/content/guide/migration-injectable.md new file mode 100644 index 0000000000000..da33ad9542e7c --- /dev/null +++ b/aio/content/guide/migration-injectable.md @@ -0,0 +1,86 @@ +# Migration to Add Missing `@Injectable()` Decorators + +## What does this schematic do? + +This schematic adds an `@Injectable()` decorator to a class +if the class has been added as a provider anywhere in the application. + +An example diff might look like the following: + +**Before:** + +```ts +export class TypeCase {...} +``` + +**After:** + +```ts +@Injectable() +export class TypeCase {...} +``` + + +There are a few cases where the decorator won't be added. For example: + + - It already has another decorator such as `@Component()`, `@Directive()` or `@Pipe()`. These decorators already cause the compiler to generate the necessary information. + - The provider definition has `useValue`, `useFactory`, or `useExisting`. In + these cases, the framework doesn't need the `@Injectable()` decorator to create the class because + because it can just use the value, + factory function, or existing instance that was provided. + + For example, for the following module definition, the schematic will check + `TypeCase`, `ProvideCase`, `ExistingClass`, and `SomeClass` to ensure they + are marked with the `@Injectable()` decorator and add one if not. + + + ```ts + @NgModule({ + providers: [ + // TypeCase needs @Injectable() + TypeCase, + // ProvideCase needs @Injectable() + {provide: ProvideCase}, + // No @Injectable() needed because the value will be used + {provide: ValueCase, useValue: 0}, + // No @Injectable() needed because factory will be used + {provide: FactoryCase, useFactory: ()=> null}, + // ExistingClass needs @Injectable() + {provide: ExistingToken, useExisting: ExistingClass}, + // SomeClass needs @Injectable() + {provide: ClassToken, useClass: SomeClass}, + // No @Injectable() needed because it has a @Pipe() decorator + PipeCase, + + ] + }) + + ``` + + +## Why is this migration necessary? + +In our docs, we've always recommended adding `@Injectable()` +decorators to any class that is provided or injected in your application. +However, older versions of Angular did allow injection of a class +without the decorator in certain cases, such as AOT mode. +This means if you accidentally omitted the decorator, your application +may have continued to work despite missing `@Injectable()` decorators in some places. +This is problematic for future versions of Angular. Eventually, we plan +to strictly require the decorator because doing so enables further +optimization of both the compiler and the runtime. This schematic +adds any `@Injectable()` decorators that may be missing to future-proof your app. + + + +## When should I be adding `@Injectable()` decorators to classes? + +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. + +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. + + +## Should I update my library? + +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. +