web-dev-qa-db-fra.com

Service angulaire 6 avec interface

Je construis une application avec Angular (6.0.7) et j'essaie de créer un service avec le nouveau:

@Injectable({
  providedIn: 'root'
})

Mais comment puis-je taper une injection avec une interface?


Le problème

J'ai 2 services, Authentication.service et SessionStorage.service. Je veux injecter le sessionstorage dans le service d'authentification. Cela peut être fait via:

constructor(private sessionStorage: SessionStorage) {
}

Pas de problème là-bas. Mais pour des besoins orientés objet, je souhaite avoir une interface au-dessus de ce service (afin de pouvoir implémenter le service localstorage en tant que service sessionstorage). Ainsi, il n’est que logique que je veuille taper la classe injectée avec l’interface, mais cela ne peut pas être fait de la même manière Angular 5 et inférieur le fait .

Alors, comment puis-je saisir l'injection dans ce service global avec mon interface?


J'ai essayé

Les typages de services angulaires décrivent une InjectableProvider, mais cela ne correspond à aucun des paramètres des frères et sœurs de InjectableProvider, ainsi cela donne une erreur au compilateur (et tslint). 

@Injectable({
  providedIn: 'root'
}, {provide: IStorageService, useClass: SessionStorage})
4
Mr.wiseguy

Cela peut être fait avec InjectionToken, qui remplace le obsolète 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
  ) {}
3
jenson-button-event

J'ai utilisé quelque chose comme le suivant pour résoudre ce problème 

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
k0zakinio

Je pense que vous ne pouvez pas utiliser d'interfaces TypeScript pour l'injection de dépendances car les interfaces TypeScript n'existent pas à l'exécution (uniquement pour la sécurité à la typographie à la compilation) .
Je suggérerais d'utiliser une classe abstract pour cela.

EDIT: Il semble que vous pouvez utiliser useClass dans le paramètre first de @Injectable, pas comme une seconde, comme dans votre exemple. En combinant cela avec la réponse de @ k0zakinio, vous obtenez:

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

Il semble également que vous deviez déclarer vos dépendances via deps ou inject, consultez ce problème de github . J'espère que cette fois ma réponse sera plus utile.

0
SirDieter

Vous pouvez utiliser quelque chose comme -

[{ provide: InterfaceName, useClass: ClassName}]
0
eduPeeth