Angular 6 сервис с интерфейсом - PullRequest
0 голосов
/ 04 июля 2018

Я создаю приложение с Angular (6.0.7) и пытаюсь создать сервис с новым:

@Injectable({
  providedIn: 'root'
})

Но как мне ввести инъекцию с помощью интерфейса?


Проблема

У меня есть 2 службы, Authentication.service и SessionStorage.service . Я хочу добавить сессионное хранилище в сервис аутентификации. Это можно сделать через:

constructor(private sessionStorage: SessionStorage) {
}

Нет проблем. Но для объектно-ориентированных целей я хочу иметь interface над этим сервисом (чтобы я мог реализовать оба сервиса localalstorage как сервис sessionstorage). Таким образом, вполне логично, что я хочу ввести введенный класс с интерфейсом, но это не может быть сделано таким же образом, как Angular 5 и ниже делает это .

Так, как я могу ввести инъекцию в этот глобальный сервис с моим интерфейсом?


Я пробовал

Типы сервисов Angular описывают InjectableProvider, но это не соответствует ни одному из параметров родственных элементов InjectableProvider, поэтому это приводит к ошибке компилятора (и tslint).

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

Ответы [ 4 ]

0 голосов
/ 22 августа 2018

Это можно сделать с помощью InjectionToken, который заменяет устаревший 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
  ) {}
0 голосов
/ 10 июля 2018

Я использовал что-то вроде следующего, чтобы решить это

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
};
0 голосов
/ 10 июля 2018

Я думаю, что вы не можете использовать интерфейсы машинописи для внедрения зависимостей, так как интерфейсы машинописи не существуют во время выполнения (только для безопасности типов во время компиляции).
Я бы предложил использовать для него абстрактный класс .

EDIT: Кажется, вы можете использовать useClass в параметре first в @Injectable, а не в качестве второго, как в вашем примере. Объединение этого с ответом @ k0zakinio приводит к:

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

Также кажется, что вам нужно объявить свои зависимости через deps или inject, закажите эту проблему github . Надеюсь, на этот раз мой ответ поможет мне.

0 голосов
/ 04 июля 2018

Вы можете использовать что-то вроде -

[{ provide: InterfaceName, useClass: ClassName}]
...