8

我注意到我的项目有很多解析器服务,尽管它们使用不同的实体和存储库托管相同的代码。所以我接受了挑战,使用泛型将它们简化为单个解析器服务:

@Injectable()
export class DetailResolver<T, R extends Repository<T>> implements Resolve<T> {

  constructor(private repositoryService: R, private router: Router) {}

  resolve(route: ActivatedRouteSnapshot, state: RouterStateSnapshot): Observable<T> {
    // use repositoryService to resolve this route
  }
}

可以指定实体类型 T 和存储库类型 R。但是我无法使用此服务:

const appRoutes: Routes = [
  // other routes
  {
    path: ':id',
    component: MessageEditComponent,
    resolve: {
      message: DetailResolver<Message, MessageService>
    }
  }
];

@NgModule({
  imports: [
    RouterModule.forChild(appRoutes)
  ],
  exports: [
    RouterModule
  ],
  providers: [
    DetailResolver<Message, MessageService>
  ]
})

一旦我在DetailResolver<Message, MessageService>编译器中指定泛型类型,我就希望我创建一个实例:

typeof DetailResolver 类型的值不可调用。你的意思是包括新的?

我不太熟悉 angular4 DI 内部。任何人都可以描述什么是错的,这个问题有什么解决方案吗?我正在使用角度 4.3。

4

1 回答 1

10

当您向注入器注册提供者时,DI 系统使用该令牌(或其他可能被视为的东西)来维护每次请求依赖项时都会引用的令牌提供者映射。

令牌通常是唯一且具有符号性的对象,因此泛型的概念在这方面直接冲突,因为令牌将用作key。泛型是设计时的产物,这是另一种说法,它们将从生成的 JavaScript 中消失,因此不会将它们的类型信息留给 Angular 在运行时查找。出于同样的原因,TypeScript 接口也不是有效的标记。

抽象类

我的第一个选择是使用abstractclasses。抽象类在这里解决了两个问题:1)虽然它们不能直接实例化,但与接口不同,它们可以包含实现细节,因此可以编译成 Javascript。2)您通过基于扩展的架构获得 DI 令牌,这可能非常适合您的架构。

在您的情况下,您可以执行以下操作:

@Injectable()
export abstract class DetailResolver<T, R extends Repository<T>> implements Resolve<T> {...}

@Injectable()
export class MessageResolver extends DetailResolver<Message, MessageService> {...}

然后在NgModule您将通过以下方式提供它:

providers: [{ provide: DetailResolver, useClass: MessageResolver }]

注入令牌

另一种选择是使用(在 Angular 4.0 之前InjectionToken称为s)。s 是专门用作 DI 令牌的对象;但是,与它们的前身不同,它们需要输入它们将注入的值的类型。OpaqueTokenInjectionTokenOpaqueToken

const MESSAGE_RESOLVER = new InjectionToken<DetailResolver<Message, MessageService>>('MESSAGE_RESOLVER');

您会注意到,您可以在创建InjectionToken实例时提供类型,以便让编译器一路支持您。当您在NgModule.

providers: [{ provide: MESSAGE_RESOLVER, useClass: MessageResolver }]

值得注意的是,useClass那里没有技术要求;提供相应选项时,任何其他选项(例如useValueuseFactory在此处均有效)。

希望这会有所帮助,并为此事提供一些澄清!

于 2017-10-12T10:28:41.050 回答