使用 Angular Ivy 抽象 @Injectable 不起作用
Abstracting @Injectable with Angular Ivy does not work
更新
简介
在Angular中使用装饰器@Injectable
提供服务。
@Injectable() // -> works
export class MyService {
constructor() {}
}
抽象@Injectable
在 Ivy 之前,可以为 @Injectable
构建抽象(例如,动态配置提供者,增强服务 class)。
以下代码段显示了如何包装 @Injectable
的示例。
function InjectableEnhanced() {
return <T extends new (...args: any[]) => InstanceType<T>>(target: T) => {
Injectable({ providedIn: "root" })(target);
};
}
使用装饰器 InjectableEnhanced
(见上文)在启用 Ivy 时不起作用。
以下代码片段会导致运行时错误。
@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 的方法吗?
复制存储库
装饰器正按预期附加到构造函数,但在创建 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
被排除在外从列表中。稍后在 运行-time 装饰器的元数据在那里,但注入器不知道它是做什么用的并且崩溃了。
我试图找到可以在 Ivy 编译器中注册新装饰器的文档,但无法做到,我不知道是否存在这样的东西。
仅供参考:我在我的其他项目中做了完全相同的事情,所以我认为会有很多人受此影响。
可以使用 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;
};
}
找到工作示例
更新
简介
在Angular中使用装饰器@Injectable
提供服务。
@Injectable() // -> works
export class MyService {
constructor() {}
}
抽象@Injectable
在 Ivy 之前,可以为 @Injectable
构建抽象(例如,动态配置提供者,增强服务 class)。
以下代码段显示了如何包装 @Injectable
的示例。
function InjectableEnhanced() {
return <T extends new (...args: any[]) => InstanceType<T>>(target: T) => {
Injectable({ providedIn: "root" })(target);
};
}
使用装饰器 InjectableEnhanced
(见上文)在启用 Ivy 时不起作用。
以下代码片段会导致运行时错误。
@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 的方法吗?
复制存储库
装饰器正按预期附加到构造函数,但在创建 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
被排除在外从列表中。稍后在 运行-time 装饰器的元数据在那里,但注入器不知道它是做什么用的并且崩溃了。
我试图找到可以在 Ivy 编译器中注册新装饰器的文档,但无法做到,我不知道是否存在这样的东西。
仅供参考:我在我的其他项目中做了完全相同的事情,所以我认为会有很多人受此影响。
可以使用 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;
};
}
找到工作示例