Typescript:使用装饰器时的类型推断

6

我很好奇为什么在Typescript中使用装饰器或注解时,编译器不能推断出类的新类型。如果我不使用装饰器,而是使用ES5中的旧方法(即手动调用装饰器),那么它显然可以正常工作。

例如,这里有一个示例,展示了这个问题:

function decorate(Target: typeof Base): IExtendedBaseConstructor {
  return class extends Target implements IExtendedBase {
    public extendedtMethod(): number {
      return 3;
    }
  };
}

interface IBase {
  baseMethod(): number;
}

interface IExtendedBase extends Base {
  extendedtMethod(): number;
}

interface IExtendedBaseConstructor {
  new(): IExtendedBase;
}

@decorate
class Base implements IBase {
  public baseMethod(): number {
    return 5;
  }
}

const test = new Base();
test.baseMethod(); // OK
test.extendedtMethod(); // NOT OK, typescript think, Base is still Base but we decorated it.

使用旧的方法,它可以正常工作:

class Base implements IBase {
  public baseMethod(): number {
    return 5;
  }
}

const ExtendedBase = decorate(Base);

const test = new ExtendedBase();
test.baseMethod(); // OK
test.extendedtMethod(); // OK

谢谢您提前的支持。


这种模式有什么优势吗?难道不是这段代码更容易理解吗? - David Sherret
你是正确的。在这种情况下,这种模式是无用的。但是新的前端框架(如Angular2)选择使用装饰器而不是继承来声明新组件。 - Cnode
我编写了一个库,为用户提供创建类API的帮助程序(注入一些参数和有用的方法)。因此,我创建了一个抽象Api类,提供功能和一个装饰器,通过“元数据”将api注册到我的框架中。在这种情况下,我的用户必须执行以下操作: `import { AbstractAPI, Api } from 'myLib'@Api(...) class UserApi extends AbstractAPI {}`我的SO问题也与此相关。如果我可以删除extends并将所有内容合并到我的装饰器“@Api”中,它将减少最终用户的打字错误。 - Cnode
哦,我明白了。谢谢!我很好奇。 - David Sherret
2个回答

3

现在这个功能无法使用。Github上有一个待处理问题,可以允许类修饰器改变类的类型。

在这个功能实现之前,我建议您采用“旧的方式”。


1

有一种方法可以只需要稍微增加一些代码就能使它工作。

对于任何类装饰器,创建一个接口来描述它的属性和方法。将其命名为与所描述的装饰器相关联的方式。在您的情况下,它可以是:

interface IDecorate {
  extendedtMethod(): number;
}

对于任何需要使用该装饰器的类,您只需创建一个与该类同名的接口,并让它扩展所有必要的装饰器接口:

@decorate
@anotherDecorator
class MyClass {
  // ...
}

interface MyClass extends IDecorate, IAnotherDecorator {}

现在,只需要关闭ESLint或TSLint对空接口的警告,你就可以准备好了。任何由装饰器添加的方法或属性现在都可以在装饰过的类内部使用。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接