Angular 6 service with interface

試著忘記壹切 提交于 2019-12-10 02:54:27

问题


I am building an application with Angular (6.0.7) and I am trying to create a service with the new:

@Injectable({
  providedIn: 'root'
})

But how can I type an injection with an Interface?


The problem

I have 2 services, Authentication.service and SessionStorage.service. I want to inject the sessionstorage into the authentication service. That can be done via:

constructor(private sessionStorage: SessionStorage) {
}

No problem there. But for Object Orientated purposes I want to have an interface above this service (so that I can implement both localstorage service as sessionstorage service). Thus it is only logical that I want to type the injected class with the interface, but this cannot be done the same way Angular 5 and lower does it.

So how can I type the injection into this global service with my interface?


I've tried

The Angular service typings describe an InjectableProvider, but this does not match any of the parameters of the siblings of InjectableProvider, so this gives a compiler (and tslint) error.

@Injectable({
  providedIn: 'root'
}, {provide: IStorageService, useClass: SessionStorage})

回答1:


This can be done with InjectionToken, which is a replacement for the obsolete OpaqueToken

export const AuthenticationProvider = new InjectionToken(
  "AuthenticationProvider",
  { providedIn: "root", factory: () => new CognitoAuthenticationProvider() }
);

...

@Injectable()
export class CognitoAuthenticationProvider implements IAuthenticationProvider {

...

@Injectable({
  providedIn: "root"
})
export class AuthenticationService {
  constructor(
    @Inject(AuthenticationProvider)
    private authenticationProvider: IAuthenticationProvider,
    private http: HttpClient
  ) {}



回答2:


I used something like the following to solve this

app.module.ts

providers: [
  { provide: AlmostInterface, useClass: environment.concrete }
  ...
]

AlmostInterface.ts

export abstract class AlmostInterface {
   abstract myMethod();
}

MyConcrete.ts

export class MyConcrete implements AlmostInterface {
   myMethod() { ... }; // implementation
}

export class MyConcreteAlternative implements AlmostInterface {
   myMethod() { ... }; // implementation
}

environment.ts

export const environment = {
  production: false,
  concrete: MyConcreteAlternative
};

environment.prod.ts

export const environment = {
  production: true,
  concrete: MyConcrete
};



回答3:


I think you can't use typescript interfaces for dependency injection as typescript interfaces don't exist at runtime (only for typesafety at compile time).
I would suggest using an abstract class for it.

EDIT: It seems you can use useClass in the first parameter of @Injectable, not as a second like your example. Combining that with @k0zakinio's answer results in:

@Injectable({
  providedIn: 'root',
  useClass: environment.concrete,
  deps: []
})
export abstract class SessionStorage { }

It also seems you need to declare your dependencies via deps or inject, checkout this github issue. I hope this time my answer is of more help.




回答4:


You can use something like -

[{ provide: InterfaceName, useClass: ClassName}]


来源:https://stackoverflow.com/questions/51174859/angular-6-service-with-interface

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!