get is deprecated: from v4.0.0 use Type<T> or InjectionToken<T>
Asked Answered
G

5

41

After switching to Angular 5.2.3, and running ng cli with a linter rule of "deprecation": true i get the following error in many of my tests:

get is deprecated: from v4.0.0 use Type<T> or InjectionToken<T>

The line that complains is something like

fixture.debugElement.injector.get(MyService)

with MyService being a class used for dependency injection.

I am at a loss to guess what the new syntax is supposed to be, as

fixture.debugElement.injector.get<MyService>(MyService)

gives a compile error that Argument of type 'typeof MyService' is not assignable to parameter of type 'Type<MyService> | InjectionToken<MyService>'.

What is the correct way to use the injector to avoid deprecation errors?

Edit: See answer below, for Angular9 update.

Edit: It seems to be related to MyService being an abstract class. If I use a non-abstract class, the .get<T>(T) syntax works.

Edit: Fix is apparently pending some PR work - https://github.com/angular/angular/pull/25222

Generalissimo answered 7/2, 2018 at 10:4 Comment(6)
please provide a code (including the decorators etc) for MyServiceDoes
Would you try fixture.debugElement.injector.get<MyService>(Type<MyService>)Biblicist
fixture.debugElement.injector.get<MyService>(MyService) should work. Type is constructor function. There should be no problems if MyService is a class. Make sure that imports are correct and so on.Dot
@Biblicist that syntax makes the linter happy, but the compiler then complains that error TS1005: '(' expected.. Also VSCode says something like cannot find 'Type' if i dont explicitly import it from @angular/core, and '[ts] Expected 0 type arguments, but got 1 if i do import it. However if i do import it, and ignore VSCode, and run the test, i get Error: StaticInjectorError(DynamicTestModule)[anonymous]: StaticInjectorError(Platform: core)[anonymous]: NullInjectorError: No provider for anonymous! Generalissimo
@Does i have a base class with no decorators: ` export abstract class MyService { } ` which is then provided to a subclass that extends MyService, and has @Injectable() decorator.Generalissimo
@estus thanks for confirming that this should be the syntax. The code and test works fine when using the deprecated form of .get (i.e. without the <T> bit), and I have verified that all types in use are imported.Generalissimo
S
27

A better you can try to convert your service as Type and then use injector like this:

import { Type } from '@angular/core';

fixture.debugElement.injector.get<MyService>(MyService as Type<MyService>)
Silverts answered 3/7, 2018 at 21:52 Comment(0)
G
9

UPDATE: For Angular9, the syntax has changed to this:

TestBed.inject<IDataService>(IDataService).

This also works for abstract classes.

In VSCode, you can fix most of your cases by this

FIND: TestBed.get\(([^\)]+)\) as .*;
REPLACE: TestBed.inject<$1>($1);

PRE Angular 9. So, it seems to be related to Abstract vs non-abstract classes.

I have posted my findings here: https://github.com/angular/angular/issues/22063 in case someone runs into the same issue.

Generalissimo answered 8/2, 2018 at 11:48 Comment(1)
Please post the relevant part of your findings here, so we can have a worthy (i.e. not link-only) answer to upvote and hence use as a basis for marking other such threads as duplicates. But then, saying that, they just told you to ask on SO... so we'll get kinda stuck in a loop there!Talmudist
L
7

As a temporary fix you can try following:

fixture.debugElement.injector.get<MyService>(MyService as any)

Lonnielonny answered 4/5, 2018 at 16:2 Comment(0)
G
6

I've worked around this by defining an injection token:

export const DATA_SERVICE = new InjectionToken('DataService');

and using it to alias my service in the module:

...
providers = [
    { provide: DataService, useFactory: dataServiceFactory },
    { provide: DATA_SERVICE, useExisting: DataService }
]
...

I can then retrieve this service directly from an Injector using the injection token, without getting the deprecation warning:

this.dataService = injector.get(DATA_SERVICE);

In my case, DataService is an abstract class and I have two concrete (@Injectable) implementations to switch between mock data and real web service data. The appropriate version is instantiated in the dataServiceFactory method.

There are two overloads to the injector.get() call and I think that without the InjectionToken the deprecated overload is being called because the type system isn't recognising typeof DataService as an InjectionToken.

Interestingly, all injections of this service to components via constructors, such as:

constructor(
    ds: DataService
) { }

currently work. Will they work when the deprecated get() overload is removed in the future?

I think this is a question for the Angular team.

Garrygarson answered 2/8, 2018 at 4:58 Comment(0)
G
1

I kept getting this linter warning even though I changed the code to match the non-deprecated get(). After upgrading the Angular CLI from 6.0.0. to 6.2.6 the warning went away.

Gauleiter answered 30/10, 2018 at 19:19 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.