Angular Provider useFactory意外注入数组问题求助
Angular自定义InjectionToken注入结果为数组而非预期Observable类型
我在Angular中通过自定义InjectionToken配置了Provider,预期注入类型为Observable<Array<string>>,但实际注入的却是Observable<Array<string>>[],导致路由守卫中调用pipe时报错“authorizedRoutes$.pipe is not a function”。
相关代码如下:
注入令牌定义
export const AUTHORIZED_ROUTE_NAMES = new InjectionToken<Observable<Array<string>>>('Names of authorized routes');
app.module.ts中的Provider配置
providers: [ // 其他配置 { provide : AUTHORIZED_ROUTE_NAMES, useFactory: (routeService : RouteService) => routeService.authorizedRouteNames$, deps: [RouteService], multi: true }, // 其他配置 ]
RouteService代码
export class RouteService { private _authorizedRouteNames$$ : BehaviorSubject<Array<string>>; get authorizedRouteNames$() : Observable<Array<string>> { return this._authorizedRouteNames$$.asObservable(); } // 从API获取值并调用_authorizedRouteNames$$.next()的代码 }
路由守卫报错代码
export const authorizedRouteGuard: CanActivateFn = (route, state) => { const authorizedRoutes$ = inject(AUTHORIZED_ROUTE_NAMES); // 逻辑处理 const path = /** 从ActivatedRouteSnapshot获取 **/ return authorizedRoutes$ pipe( map((routes) => { return routes.indexOf(path) > -1; } ) }
问题原因
问题出在Provider配置中的multi: true参数:
当为InjectionToken的提供者设置multi: true时,Angular会将所有绑定到该令牌的提供者实例收集到一个数组中返回,而不是返回单个实例。你的注入令牌类型定义的是单个Observable<Array<string>>,但因为multi: true的存在,inject()实际返回的是该类型的数组,自然无法直接调用pipe方法。
解决方案
根据你的实际需求选择以下两种方案:
- 仅需单个提供者实例(推荐)
直接移除Provider配置中的multi: true,这样inject(AUTHORIZED_ROUTE_NAMES)就会返回预期的单个Observable<Array<string>>实例:
providers: [ // 其他配置 { provide : AUTHORIZED_ROUTE_NAMES, useFactory: (routeService : RouteService) => routeService.authorizedRouteNames$, deps: [RouteService] // 移除multi: true }, // 其他配置 ]
- 确实需要多个提供者实例
如果你的业务场景需要多个地方为该令牌提供值,那么需要修改注入令牌的类型定义为数组类型,同时在路由守卫中处理数组中的每个Observable:
// 修改注入令牌类型 export const AUTHORIZED_ROUTE_NAMES = new InjectionToken<Observable<Array<string>>[]>('Names of authorized routes'); // 路由守卫中修改处理逻辑 export const authorizedRouteGuard: CanActivateFn = (route, state) => { const authorizedRoutesList$ = inject(AUTHORIZED_ROUTE_NAMES); const path = /** 从ActivatedRouteSnapshot获取 **/ // 合并所有Observable的结果,比如取所有路由的并集 return combineLatest(authorizedRoutesList$) .pipe( map(allRoutes => { const mergedRoutes = allRoutes.flat(); return mergedRoutes.indexOf(path) > -1; }) ); }
内容的提问来源于stack exchange,提问作者Jason
相关产品推荐
相关产品推荐

