我正在尝试创建一个类装饰器,该类装饰器使用一个类,其中构造函数的第一个参数为已定义类型,而其余参数则可以自由选择。
在装饰类中添加更多参数时,会遇到上述错误。
试验1:在没有参数属性的情况下设置修饰类的其他参数。这行得通,但随后迫使我去做:在构造函数中使用this.property = property;
。
试验2:将装饰类的其他参数设置为可选。但是当使用"strict": true
设置tsconfig时,则每次引用该属性时,都需要使用! this!.property
。
export interface ServiceInstance<T> {
children: Array<ServiceInstance<T>>;
}
export type ServiceConstructor<T> = new (children: Array<ServiceInstance<T>>, ...args: any) => ServiceInstance<T>;
export function ServiceDecorator<T>() {
return function extendService(BaseService: ServiceConstructor<T>) {
class ExtendedService extends BaseService {}
return ExtendedService as ServiceConstructor<T>;
};
}
我想做的是:
@ServiceDecorator<string>()
class ServiceFoo {
constructor(public children: Array<ServiceInstance<string>>, private bar: number) {}
}
这将引发错误:Property 'bar' is missing in type 'ServiceInstance<string>' but required in type 'ServiceFoo'.ts(1238)
答案 0 :(得分:1)
问题是装饰器返回的类型必须与您要装饰的类型兼容。您返回的是ServiceConstructor<T>
,虽然在这种情况下通常就足够了,但是TypeScript很难记住T
周围的细节(这可能是一个错误,但是您仍然可以在这里解决) 。要更改的第一件事是,不要使用类型参数T
并说要返回ServiceConstructor<T>
,而要创建类型参数Ctor extends ServiceConstructor<unknown>
。
接下来您会注意到,BaseService
不能被扩展,因为TypeScript仅允许您从泛型函数类型的特定模式进行扩展。您需要简化ServiceConstructor
:
export type ServiceConstructor<T> = new (...args: any[]) => ServiceInstance<T>;
最后,您需要将类型参数移至内部函数,因为在编写@ServiceDecorator()
时,您将在实际修饰该类之前调用ServiceDecorator()
-但您需要使该类周围推断。
总体而言,您的代码应该最终看起来像这样
export interface ServiceInstance<T> {
children: Array<ServiceInstance<T>>;
}
export type ServiceConstructor<T> = new (
...args: any[]
) => ServiceInstance<T>;
export function ServiceDecorator() {
return function extendService<Ctor extends ServiceConstructor<unknown>>(BaseService: Ctor) {
let x = new BaseService([])
class ExtendedService extends BaseService {}
return ExtendedService;
};
}
@ServiceDecorator()
class ServiceFoo {
constructor(public children: Array<ServiceInstance<string>>, private bar: number) {}
}
请注意,内部函数不再需要类型声明。