代码之家  ›  专栏  ›  技术社区  ›  Kevin Beal

如何注释接受类并返回具有静态成员的工厂的函数?

  •  1
  • Kevin Beal  · 技术社区  · 8 年前

    类似 this question ,但我希望类上的静态成员也可用。

    这就是我正在尝试的:

    function noNew<T>(clazz: new () => T): { (): T }
    function noNew<T, T1>(clazz: new (arg1: T1) => T): { (arg1: T1): T }
    function noNew<T>(clazz: new (...a: any[]) => T): { (...b: any[]): T } {
        const factory = (...args: any[]) => {
            return new clazz(...args);
        };
    
        // I want the return type annotation to be aware of this step
        Object.assign(factory, clazz);
    
        return factory;
    }
    
    class Test {
        static one() {}
        two: 'two';
    }
    
    const test = noNew(Test);
    test.one(); // <- unresolved function or method 'one'
    

    如您所见,typescript不知道我在返回值中添加了静态成员。如何将其表示为注释?

    如果可以排除,则可获得额外积分 test.prototype

    1 回复  |  直到 8 年前
        1
  •  2
  •   jcalz    8 年前

    这样怎么样:

    // works for some constructor types
    type ConstructorToFunction<C extends new (...args: any[]) => any> = (
      C extends (new () => infer T) ? () => T :
      C extends (new (a: infer A) => infer T) ? (a: A) => T :
      C extends (new (a: infer A, b: infer B) => infer T) ? (a: A, b: B) => T :
      C extends (new (...args: any[]) => infer T) ? (...args: any[]) => T :
      C // bail out
    ) & { [K in Exclude<keyof C, 'prototype'>]: C[K] }
    

    我用的是 conditional types 在TypeScript 2.8中引入,试图表示构造函数到具有相同参数的函数的转换。大条件部分取代了重载集,并且与 {[K in Exclude... 负责复制静态零件。

    下面是我如何键入 noNew() 功能:

    function noNew<C extends new (...args: any[]) => any>(
      clazz: C
    ): ConstructorToFunction<C>;
    function noNew(
      clazz: new (...args: any[]) => any
    ): { (...args: any[]): any } {
      const factory = (...args: any[]) => {
        return new clazz(...args);
      };
      Object.assign(factory, clazz);
      return factory;
    }
    

    单一重载仍然很有用,因为返回条件类型的函数如果没有大量的类型断言就很难实现,因此重载将我从中解脱出来。

    让我们看看它是否有效:

    class Test {
      static one() { }
      two: 'two' = 'two';
    }
    
    const test = noNew(Test);
    test.one(); // works
    

    看起来不错。希望有帮助!