【问题标题】:TypeScript declaration for polymorphic decorator多态装饰器的 TypeScript 声明
【发布时间】:2017-07-25 14:50:51
【问题描述】:

我正在为react-tracking 编写环境声明。它公开了一个 track 装饰器,可以在类 方法上使用。

来自文档的简化示例:

import track from 'react-tracking'

@track({ page: 'FooPage' })
export default class FooPage extends React.Component {

  @track({ action: 'click' })
  handleClick = () => {
    // ...
  }
}

在我的环境声明文件中,我希望能够执行以下操作并让 TypeScript 选择正确的重载:

declare function track(trackingInfo?: any, options?: any): <T>(component: T) => T
declare function track(trackingInfo?: any, options?: any): any

export default track

虽然这对组件类很有效,但对于具有以下错误的方法却失败了:

[ts] Unable to resolve signature of method decorator when called as an expression.

查看 TS 为这个装饰器应用程序选择的类型表明它没有回退到应该匹配任何内容的签名,而是回退到组件类之一。

是否可以输入多态装饰器?如果是这样,我做错了什么?


更新:这是一个简化的简化示例。

第一个是单态的,按预期工作:

function trackClass(trackingInfo?: any, options?: any): ClassDecorator {
  return null
}

function trackMethod(trackingInfo?: any, options?: any): MethodDecorator {
  return null
}

@trackClass({})
class Foo {
  @trackMethod({})
  someMethod() {}
}

第二个例子是多态的,对两者都失败了:

function track(trackingInfo?: any, options?: any): ClassDecorator | MethodDecorator {
  return null
}

@track({})
class Bar {
  @track({})
  someMethod() {}
}

【问题讨论】:

  • 第二个例子不起作用,因为你有一个函数是 ClassDecorator | MethodDecorator - 你想说返回类型是 ClassDecorator &amp; MethodDecorator 因为它会“做正确的事”装饰器被调用。

标签: typescript polymorphism decorator


【解决方案1】:

TypeScript 的 lib.d.ts 有一个 ClassDecorator 和一个 MethodDecorator 类型:

declare type ClassDecorator = <TFunction extends Function>(target: TFunction) => TFunction | void;

declare type MethodDecorator = <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>) => TypedPropertyDescriptor<T> | void;

您可以做以下两件事之一:

  1. 创建一个具有与两者兼容的重载的类型:

    interface TrackDecorator {
        // Class decorator overload
        <TFunction extends Function>(target: TFunction): TFunction;
    
        // Property decorator overload
        <T>(target: Object, propertyKey: string | symbol, descriptor: TypedPropertyDescriptor<T>): TypedPropertyDescriptor<T>;
    }
    
    export default function track(trackingData?: object): TrackDecorator;
    
  2. 派生一个类型以适当地组合重载。

    interface TrackDecorator extends ClassDecorator, MethodDecorator { }
    export default function track(trackingData?: object): TrackDecorator;
    

前者允许您更具体,但后者会将您绑定到 TypeScript 为装饰器考虑的任何版本(换句话说,如果规范发生变化,则暗示react-tracking 支持任一版本)。

【讨论】:

  • 到目前为止,谢谢,丹尼尔!我明白你在说什么,但仍然无法找到真正让它发挥作用的方法。 track 函数返回一个类装饰器函数或一个方法装饰器函数,我已经用一个简化的示例更新了我的帖子,该示例仅显示了返回其中一种类型的问题。
  • 我发现了问题。当我使用dts-gen 创建新的DefinitelyTyped 包时,它在tsconfig.json 中设置了lib: "es6",而我显然需要target: "es6"。现在您的建议开始按预期工作。如果这是有道理的,您能否更新您的答案以包括在内,以便我可以接受答案?
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2016-11-26
  • 1970-01-01
  • 2011-02-20
  • 2017-06-23
  • 1970-01-01
  • 1970-01-01
  • 2019-10-02
相关资源
最近更新 更多