Angular提供者泛型应用:父类成员泛型化且无需修改依赖组件
解决方案:泛型Parent类+Angular依赖注入令牌
完全可以将Parent类的membervar声明为泛型,同时保留切换提供者的灵活性,且无需修改依赖组件。以下是具体实现步骤:
1. 改造Parent为泛型抽象类
将Parent定义为泛型抽象类,明确membervar的类型约束:
export abstract class Parent<T> { abstract membervar: T; }
2. 子类继承时指定具体泛型类型
让ChildA和ChildB继承泛型Parent并指定各自的membervar类型:
// 假设ObjectA、ObjectB是已定义的业务类型 export class ChildA extends Parent<ObjectA> { membervar: ObjectA; constructor() { super(); this.membervar = new ObjectA(); } } export class ChildB extends Parent<ObjectB> { membervar: ObjectB; constructor() { super(); this.membervar = new ObjectB(); } }
3. 创建注入令牌解决泛型擦除问题
由于TypeScript泛型在运行时会被擦除,直接用Parent作为DI令牌会导致类型丢失,因此需要创建一个InjectionToken:
import { InjectionToken } from '@angular/core'; // 定义泛型注入令牌,默认用unknown兼容所有类型 export const PARENT_SERVICE = new InjectionToken<Parent<unknown>>('Parent Service');
4. 注册提供者并灵活切换
在app.module.ts中注册提供者,切换子类仅需修改useClass:
import { NgModule } from '@angular/core'; import { PARENT_SERVICE } from './your-file-path'; import { ChildA, ChildB } from './your-file-path'; @NgModule({ // ...其他模块配置 providers: [ { provide: PARENT_SERVICE, useClass: ChildA } // 切换为ChildB只需替换这里 ] }) export class AppModule { }
5. 组件中注入并使用(无需修改组件即可切换)
组件通过注入令牌获取服务,可通过两种方式处理类型:
方式一:依赖公共接口(推荐)
如果ObjectA和ObjectB有公共行为,定义一个公共接口,让两者实现该接口:
export interface CommonBusiness { execute(): void; } // 确保ObjectA、ObjectB都实现CommonBusiness export class ObjectA implements CommonBusiness { execute() { /* ... */ } } export class ObjectB implements CommonBusiness { execute() { /* ... */ } }
此时Parent的泛型约束为该接口,组件注入后可直接调用公共方法,无需关心具体类型:
import { Component, Inject } from '@angular/core'; import { PARENT_SERVICE } from './your-file-path'; import { Parent } from './your-file-path'; import { CommonBusiness } from './your-file-path'; export class SomeComponent { constructor( @Inject(PARENT_SERVICE) private aService: Parent<CommonBusiness> ) { // 直接调用公共方法,切换ChildA/ChildB时无需修改组件 this.aService.membervar.execute(); } }
方式二:类型断言(无公共接口时使用)
如果ObjectA和ObjectB无公共接口,组件中可通过类型断言获取具体类型,切换提供者时仅需修改断言类型(若组件无需直接操作membervar的特有属性,甚至无需修改):
import { Component, Inject } from '@angular/core'; import { PARENT_SERVICE } from './your-file-path'; import { Parent } from './your-file-path'; import { ObjectA } from './your-file-path'; export class SomeComponent { constructor( @Inject(PARENT_SERVICE) private aService: Parent<unknown> ) { // 断言为当前提供者对应的类型 const businessVar = this.aService.membervar as ObjectA; // 操作特有属性/方法 businessVar.specificMethodOfA(); } }
内容的提问来源于stack exchange,提问作者Murmulodi
相关产品推荐
相关产品推荐

