我尝试装饰的类的实例缺少TypeScript报告属性

时间:2019-07-09 07:50:51

标签: typescript

我正在尝试创建一个类装饰器,该类装饰器使用一个类,其中构造函数的第一个参数为已定义类型,而其余参数则可以自由选择。

在装饰类中添加更多参数时,会遇到上述错误。

试验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)

1 个答案:

答案 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) {}
}

请注意,内部函数不再需要类型声明。