web-dev-qa-db-ja.com

Angular 6インターフェース付きサービス

Angular(6.0.7)そして、新しいサービスを作成しようとしています:

@Injectable({
  providedIn: 'root'
})

しかし、インターフェイスでどのように注入を入力できますか?


問題

2つのサービス、Authentication.serviceおよびSessionStorage.serviceがあります。セッションストレージを認証サービスに注入したい。それは次の方法で実行できます。

constructor(private sessionStorage: SessionStorage) {
}

問題ありません。しかし、オブジェクト指向の目的のために、このサービスの上にinterfaceが必要です(両方のlocalstorageサービスをsessionstorageサービスとして実装できるようにするため)。したがって、注入されたクラスをインターフェイスで入力したいのは論理的ですが、これは同じ方法で行うことはできません Angular 5以下はそれを行います

それでは、このグローバルサービスにインターフェイスでインジェクションを入力するにはどうすればよいですか?


試した

AngularサービスタイピングはInjectableProviderを記述しますが、これはInjectableProviderの兄弟のパラメータのいずれとも一致しないため、コンパイラ(およびtslint )エラー。

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

これは、廃止された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
  ) {}
6

これを解決するために次のようなものを使用しました

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
};
4
k0zakinio

実行時にはTypeScriptインターフェイスは存在しないため(コンパイル時の型安全性のみ)、依存性注入にTypeScriptインターフェイスを使用できないと思います。
抽象クラスを使用することをお勧めします。

編集:@InjectableのfirstパラメーターでuseClassを使用できるようです。例のように秒として使用することはできません。それを@ k0zakinioの回答と組み合わせると、次のようになります。

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

また、depsまたはinjectを介して依存関係を宣言する必要があるようです。これを確認してください github issue 。今回の回答がもっと役立つことを願っています。

2
SirDieter

次のようなものを使用できます-

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