angular/aio/content/guide/migration-injectable.md
Paul Gschwendtner 5b04abd5c0 docs: update title of v9 injectable migration guide (#34125)
The missing-injectable migration has been updated to handle a breaking change that is
unrelated to missing ´@Injectable` decorators. Though, the breaking change will be handled
as part of this migration since we did not want to create another migration (with all the boilerplate etc.)

The guide has been already updated to reflect the new pattern the migration handles, but we
should also rename the title of the guide to something that also mentions the other pattern.

Not renaming the guide URL since it is referenced in past releases and it's safer to keep the old
URL. The important thing is to change the actual rendered title.

PR Close #34125
2019-12-02 11:21:50 -08:00

110 lines
4.0 KiB
Markdown

# Migration for missing `@Injectable()` decorators and incomplete provider definitions
### What does this schematic do?
1. This schematic adds an `@Injectable()` decorator to classes which are provided in the
application but are not decorated.
2. The schematic updates providers which follow the `{provide: SomeToken}` pattern
to explicitly specify `useValue: undefined`.
**Example for missing `@Injectable()`**
_Before migration:_
```typescript
export class MyService {...}
export class MyOtherService {...}
export class MyThirdClass {...}
export class MyFourthClass {...}
export class MyFifthClass {...}
@NgModule({
providers: [
MyService,
{provide: SOME_TOKEN, useClass: MyOtherService},
// The following classes do not need to be decorated because they
// are never instantiated and just serve as DI tokens.
{provide: MyThirdClass, useValue: ...},
{provide: MyFourthClass, useFactory: ...},
{provide: MyFifthClass, useExisting: ...},
]
})
```
_After migration:_
```ts
@Injectable()
export class MyService {...}
@Injectable()
export class MyOtherService {...}
export class MyThirdClass {...}
export class MyFourthClass {...}
export class MySixthClass {...}
...
```
Note that `MyThirdClass`, `MyFourthClass` and `MyFifthClass` do not need to be decorated
with `@Injectable()` because they are never instantiated, but just used as a [DI token][DI_TOKEN].
**Example for provider needing `useValue: undefined`**
This example shows a provider following the `{provide: X}` pattern. The provider needs to be
migrated to a more explicit definition where `useValue: undefined` is specified.
_Before migration_:
```typescript
{provide: MyToken}
```
_After migration_:
```typescript
{provide: MyToken, useValue: undefined}
```
### Why is adding `@Injectable()` 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.
### Why is adding `useValue: undefined` necessary?
Consider the following pattern:
```typescript
@NgModule({
providers: [{provide: MyService}]
})
```
Providers using this pattern will behave as if they provide `MyService` as [DI token][DI_TOKEN]
with the value of `undefined`. This is not the case in Ivy where such providers will be interpreted
as if `useClass: MyService` is specified. This means that these providers will behave differently
when updating to version 9 and above. To ensure that the provider behaves the same as before, the
DI value should be explicitly set to `undefined`.
### When should I be adding `@Injectable()` decorators to classes?
Any class that is provided must have an `@Injectable()` decorator. The decorator is necessary
for the framework to properly create an instance of that class through DI.
However, classes which are already decorated with `@Pipe`, `@Component` or `@Directive` do not
need both decorators. The existing class decorator already instructs the compiler to generate the
needed information.
### Should I update my library?
Yes, if your library has any classes 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.
Additionally, providers in your library that follow the described `{provide: X}` pattern should be
updated to specify an explicit value. Without explicit value, these providers can behave
differently based on the Angular version in applications consuming your library.
[DI_TOKEN]: guide/glossary#di-token