wake-up-neo.com

Angular 6 Service mit Schnittstelle

Ich baue eine Anwendung mit Angular (6.0.7) und versuche, einen Dienst mit dem neuen zu erstellen:

@Injectable({
  providedIn: 'root'
})

Aber wie kann ich eine Injektion mit einer Schnittstelle eingeben?


Das Problem

Ich habe 2 Dienste, Authentication.service und SessionStorage.service. Ich möchte den Sessionstorage in den Authentifizierungsdienst einfügen. Das geht über:

constructor(private sessionStorage: SessionStorage) {
}

Kein Problem da. Für objektorientierte Zwecke möchte ich jedoch eine interface über diesem Dienst haben (damit ich sowohl den localstorage-Dienst als Sitzungsspeicherdienst implementieren kann). Daher ist es nur logisch, dass ich die injizierte Klasse mit der Schnittstelle eingeben möchte, aber dies kann nicht auf die gleiche Art und Weise erfolgen - Angular 5 und niedriger macht es .

Wie kann ich also mit meiner Schnittstelle die Injektion in diesen globalen Dienst eingeben?


Ich habe es versucht

Die Angular-Servicetypings beschreiben eine InjectableProvider, die jedoch mit keinem der Parameter der gleichgeordneten Elemente von InjectableProvider übereinstimmt. Daher wird ein Compiler- (und TSLINT-) Fehler ausgegeben. 

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

Dies kann mit InjectionToken erfolgen, das ein Ersatz für die veraltete OpaqueToken ist.

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

Ich habe etwas wie das Folgende verwendet, um das zu lösen 

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

Ich denke, Sie können TypeScript-Interfaces nicht für die Abhängigkeitsinjektion verwenden, da TypeScript-Interfaces zur Laufzeit nicht existieren (nur für Typensicherheit zur Kompilierzeit) .
Ich würde vorschlagen, eine abstract-Klasse dafür zu verwenden.

EDIT: Anscheinend können Sie useClass im first -Parameter von @Injectable verwenden, nicht als eine Sekunde wie in Ihrem Beispiel. Die Kombination mit @ k0zakinios Antwort ergibt:

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

Es scheint auch, dass Sie Ihre Abhängigkeiten über deps oder inject angeben müssen, überprüfen Sie diese github issue . Ich hoffe, diesmal ist meine Antwort mehr Hilfe.

0
SirDieter

Sie können etwas verwenden wie -

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