1

我有以下代码片段,我觉得很难理解:

  export class Record{

  };

  export class RecordMissingExtendsError{
      constructor(r:any){

      }
  }


  export function Model() {
    return <T extends { new(...args: any[]): {} }>(ctr: T) => {
        if (!(ctr.prototype instanceof Record)) {
            throw new RecordMissingExtendsError(ctr);
        }

        return (class extends ctr {
            constructor(...args: any[]) {
                const [data] = args;
                if (data instanceof ctr) {
                    return data;
                }
                super(...args);
                (this as any)._completeInitialization();
            }
        });
    };
}

我很难理解上面的代码并且理解如下:

模型返回类型 T(我知道泛型是什么,所以不用担心解释泛型)其中

T extends { new(...args: any[]): {}

上面是什么意思?是否要保留现有属性以及额外的附加功能?

另外你能解释一下函数返回类型吗?我们是否要向 T 添加一个额外的构造函数?

(class extends ctr {
            constructor(...args: any[]) {
                const [data] = args;
                if (data instanceof ctr) {
                    return data;
                }
                super(...args);
                (this as any)._completeInitialization();
            }
        });
4

2 回答 2

1

T extends { new(...args: any[]): {} }表示T必须是构造函数(即类)。构造函数参数和返回类型无关紧要(T可以有任意数量的参数,并且可以返回任何扩展的类型,{}实际上是任何对象类型)。

如果直接调用,T则将是类。用于键入此装饰器的方法基本上是 mixins(在此处为 typescript 描述)。

该函数的返回值将是一个继承装饰类的类。因此,它不是添加构造函数,而是用新构造函数替换原始构造函数,并通过调用调用原始构造函数super

在我看来,在这种情况下,泛型有点矫枉过正。它们对 mixin 很有用,因为它们将原始类从输入参数转发到输出参数(并且 mixin 将成员添加到类型中)。但是由于装饰器不能改变类型的结构,所以没有什么可以转发的。另外,不是构造函数返回,{}而是将其键入返回,Record因为您在运行时检查它,还不如在编译时检查它:

export class Record{
    protected _completeInitialization(): void {}
};

export function Model() {
  return (ctr: new (...a: any[]) => Record ) => {
      if (!(ctr.prototype instanceof Record)) {
          throw new RecordMissingExtendsError(ctr);
      }

      return (class extends ctr {
          constructor(...args: any[]) {
              const [data] = args;
              if (data instanceof ctr) {
                  return data;
              }
              super(...args);
              this._completeInitialization(); // no assertion since constructor returns a record
          }
      });
  };
}

@Model()
class MyRecord extends Record { }

@Model()// compile time error, we don't extend Record
class MyRecord2  { }
于 2018-09-18T13:59:16.053 回答
1

类型约束

T extends { new(...args: any[]): {} }

在这里,类型T被限制为任何扩展的类型{ new(...args: any[]): {} }。这里的格式可能有点混乱 - 格式正确,类型如下所示:

{
    new(...args: any[]): {}
}

这描述了一个所谓的newable,它是某种需要使用调用new的函数对象。例如:

let A: { new(): any; };
A(); // not ok
new A(); // ok

let B: { new(foo: string): any; };
B(); // not ok
new B(); // not ok, param missing
new B('bar'); // ok

...args: any[]只是一个rest参数声明,返回类型声明,{}意味着需要返回一个对象。TypeScript 将假定返回的对象没有任何属性

返回匿名类

至于返回类型:由于Model装饰器函数是类装饰器,它可以返回一个类本身。如果它确实返回一个类,则将使用该类而不是装饰类。

如果类装饰器返回一个值,它将用提供的构造函数替换类声明。

来自 TS 手册

例如:

// `ctr` is a common abbreviation for "constructor"
function Decorate(ctr: Function) {
    return class {
        constructor() {
            super();
            console.log('decorated');
        }
    };
}

@Decorate
class A {
    constructor() {
        console.log('A');
    }
}

new A(); // this will log: "A" first, then "decorated"
于 2018-09-18T14:55:27.863 回答