Angular 6 服务与接口

Angular 6 service with interface

我正在使用 Angular (6.0.7) 构建一个应用程序,我正在尝试使用新的:

创建一个服务
@Injectable({
  providedIn: 'root'
})

但是如何使用接口输入注入?


问题

我有 2 个服务,Authentication.serviceSessionStorage.service。我想将会话存储注入身份验证服务。这可以通过以下方式完成:

constructor(private sessionStorage: SessionStorage) {
}

没问题。但是出于面向对象的目的,我希望在此服务之上有一个 interface(这样我就可以将本地存储服务实现为会话存储服务)。因此,我想用接口输入注入的 class 是合乎逻辑的,但这不能以相同的方式完成 .

那么如何使用我的界面将注入输入到这个全局服务中呢?


我试过了

Angular 服务类型描述了一个 InjectableProvider,但这与 InjectableProvider 的兄弟姐妹的任何参数都不匹配,因此这会产生编译器(和 tslint)错误.

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

你可以使用类似 -

[{ provide: InterfaceName, useClass: ClassName}]

我使用了类似下面的方法来解决这个问题

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

我认为你不能使用类型脚本接口进行依赖注入,因为类型脚本接口在运行时不存在(仅用于编译时的类型安全)。
我建议使用摘要class

编辑: 看来您可以在@Injectable 的first 参数中使用useClass,而不是像您的示例那样使用第二个参数。将其与 @k0zakinio 的答案结合起来:

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

您似乎还需要通过 depsinject 声明您的依赖项,请查看此 github issue。希望这次我的回答能对您有所帮助

这可以用 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
  ) {}