使用 Angular Ivy 抽象 @Injectable 不起作用
Posted
技术标签:
【中文标题】使用 Angular Ivy 抽象 @Injectable 不起作用【英文标题】:Abstracting @Injectable with Angular Ivy does not work 【发布时间】:2020-04-27 12:06:51 【问题描述】:更新
为这个问题打开了问题https://github.com/angular/angular/issues/34721简介
在 Angular 中使用装饰器 @Injectable
提供服务。
@Injectable() // -> works
export class MyService
constructor()
抽象@Injectable
在 Ivy 之前,可以为 @Injectable
构建抽象(例如,用于动态配置提供程序、增强服务类)。
以下 sn-p 显示了如何包装 @Injectable
的示例。
function InjectableEnhanced()
return <T extends new (...args: any[]) => InstanceType<T>>(target: T) =>
Injectable( providedIn: "root" )(target);
;
在启用 Ivy 时,使用装饰器 InjectableEnhanced
(见上文)不起作用。
以下代码被截断会导致运行时错误。
@InjectableEnhanced() // -> does not work
export class MyService
constructor()
运行时错误
使用 @InjectableEnhanced
和 angular/cli 编译服务有效,但浏览器中显示以下错误。对应的项目可以在https://github.com/GregOnNet/ng-9-inject.git找到。
也许,Angular 编译器做了一些代码转换,但不能再在其他装饰器中解析 @Injectable。
查看 Angular 存储库,可以在 injectable.ts
中找到对 JIT 编译器的引用(请参阅:https://github.com/angular/angular/blob/master/packages/core/src/di/injectable.ts#L14)。
问题
还有没有办法抽象出@Injectable?
复制库
https://github.com/GregOnNet/ng-9-inject.git
【问题讨论】:
【参考方案1】:可以使用一些 Angular 的内部 API 创建自定义提供程序:
import ɵɵdefineInjectable, ɵɵinject from "@angular/core";
export function InjectableEnhanced()
return <T extends new (...args: any[]) => InstanceType<T>>(target: T) =>
(target as any).ɵfac = function()
throw new Error("cannot create directly");
;
(target as any).ɵprov = ɵɵdefineInjectable(
token: target,
providedIn: "root",
factory()
// ɵɵinject can be used to get dependency being already registered
const dependency = ɵɵinject(Dependency);
return new target(dependency);
);
return target;
;
可以在https://github.com/GregOnNet/ng-9-inject找到工作示例
【讨论】:
似乎在 Angular 12 中ɵfac
只是一个吸气剂,不可能为它分配一个函数。任何想法如何克服这个问题?
嗨,我最近更新了我的库,我的库仍然可以使用。但我会仔细检查。
好的,我也验证过了。所以它与 AOT=true 一起工作。但是对于使用 Ivy Angular 的非 aot 构建,添加了您无法修改的 ɵfac
和 ɵprov
getter。对于这种情况,创建普通的 Injectable
实例仍然像以前一样工作。我只想知道是否有办法知道构建是否在运行时...
好的,如果其他人有同样的问题,这里是如何解决它。而不是(target as any).ɵprov = ɵɵdefineInjectable
使用Object.defineProperty(target, 'ɵprov', .....)
【参考方案2】:
装饰器按预期附加到构造函数,但是当 AppComponent
创建时,注入器尝试解析提供程序并崩溃。
我认为错误消息只是组件构造失败时的一般错误,但是当 Angular 尝试为 AppComponent
构造函数获取可注入时发生错误。
如果您记录服务的构造函数,您可以看到提供者元数据已附加:
@InjectableEnhanced()
export class MyService
constructor()
console.log((MyService as object).prototype.constructor.hasOwnProperty('ɵprov'));
// prints "true"
当我尝试检查该属性时,它会触发错误:
try
console.log((MyService as object).prototype.constructor.ɵprov);
catch (err)
console.log(err); // prints the same error message
我认为该属性是一个 getter 属性,它解析为提供者的实例,这就是崩溃的原因。
我能找到的关于 Angular 的最接近的问题是这个,但它仍然是开放的:
https://github.com/angular/angular/issues/31495
所以我觉得 Ivy 编译器可能正在搜索 @Injectable()
的源代码并构建预期提供者的列表,但它没有看到这个新的装饰器,因此 MyService
被排除在列表之外。稍后在运行时,装饰器的元数据就在那里,但注入器不知道它的用途并崩溃。
我试图找到一些文档,您可以在其中使用 Ivy 编译器注册一个新的装饰器,但没能做到,我不知道这样的事情是否存在。
仅供参考:我在我的其他一个项目中做同样的事情,所以我认为会有很多人受此影响。
【讨论】:
谢谢您的回答。 ? 它真的帮助我更深入地挖掘。我读了github.com/angular/angular/issues/31495,也认为这可能是相关的。不过,我将打开另一个问题,因为 IoC 也在这里受到影响。 @GregorWoiwode 你能用你打开的问题的链接更新你的问题,以便其他人可以找到它。谢谢。以上是关于使用 Angular Ivy 抽象 @Injectable 不起作用的主要内容,如果未能解决你的问题,请参考以下文章
在没有 Ivy 的 Angular 10 库中导入 RouterModule