【问题标题】:TypeScript: self-referencing return type for static methods in inheriting classesTypeScript:继承类中静态方法的自引用返回类型
【发布时间】:2015-12-04 21:47:34
【问题描述】:

使用 TypeScript 1.7 中的Polymorphic this,正如我发现的here,我们可以在返回类型为this 的类中定义一个方法,并且自动地,任何扩展该类并继承方法的类将将它们的返回类型设置为各自的this 类型。像这样:

class Model {
  save():this {    // return type: Model
    // save the current instance and return it
  }
}

class SomeModel extends Model {
  // inherits the save() method - return type: SomeModel
}

但是,我所追求的是继承static 方法,其返回类型引用类本身。最好在代码中描述:

class Model {
  static getAll():Model[] {
    // return all recorded instances of Model as an array
  }

  save():this {
    // save the current instance and return it
  }
}

class SomeModel extends Model {
  // inherits the save() method - return type: SomeModel
  // also inherits getAll() - return type: Model (how can we make that SomeModel?)
}

也许我必须想出一种不同的方法来实现它,因为 TypeScript 1.7 中的多态 this 不支持 static 方法设计

编辑:我想我们会看到这个 Github 问题如何结束:https://github.com/Microsoft/TypeScript/issues/5863

【问题讨论】:

    标签: generics inheritance static typescript self-reference


    【解决方案1】:

    这在 TypeScript 2.0+ 中是可行的。通过使用内联 { new(): T } 类型来捕获 this,您将得到您想要的:

    type Constructor<T> = { new (): T }
    
    class BaseModel {
      static getAll<T>(this: Constructor<T>): T[] {
        return [] // dummy impl
      }
      
      /**
       * Example of static method with an argument:
       */
      static getById<T>(this: Constructor<T>, id: number): T | undefined {
        return // dummy impl
      }
    
      save(): this {
        return this // dummy impl
      }
    }
    
    class SubModel extends BaseModel {}
    
    const sub = new SubModel()
    const savedSub: SubModel = sub.save()
    
    // Behold: SubModel.getAll() returns SubModels, not BaseModel
    const savedSubs: SubModel[] = SubModel.getAll()
    

    请注意,getAll 仍然不希望这种类型的参数。

    有关详细信息,请参阅https://www.typescriptlang.org/docs/handbook/2/generics.html#using-class-types-in-genericshttps://stackoverflow.com/a/45262288/1268016

    【讨论】:

    • 如果您在getAll 的函数实现中使用其他静态方法,例如this.someOtherStaticMethod(),则提供者会抱怨。你可以通过(this as any) 来解决这个问题
    • @Flion 每次你投到any,你都会让 Hejlsberg 先生哭泣。您可以创建一个BaseModelClass 来捕获静态签名,而不是使用内联的{ new(): T } 类型。有关工作示例,请参阅 github.com/Vincit/objection.js/blob/master/typings/objection/…
    • 谢谢,我同意,最好尽可能让 Hejlsberg 先生高兴 :) .. BaseModelClass 在大多数情况下工作得更整洁。但我仍然对getAll 中的this.someOtherPrivateStaticMethod() 有疑问。接口不允许私有声明,但我需要在接口中定义它。如果我将它定义为 public,当我在一个子类上调用 getAll 时,编译器会抱怨它在一个子类中是私有的,但在另一个子类中没有
    • 如何在不强制转换的情况下使用其他静态方法?我有一个基类,但我不想为我的基类创建一个大接口......当我尝试使用 this.otherStatic 时,它会抱怨。如果我使用 (this.constructor).otherStatic,它说我无法将 this=>T 转换为 ....
    • @yalpsideman 我刚刚为您更新了代码。
    【解决方案2】:

    基于simplest answerGitHub issue,您可以像这样使用InstanceType&lt;&gt;

    class Foo {
        static create<T extends typeof Foo>(this: T): InstanceType<T> {
            return new this() as InstanceType<T>
        }
    
        static getAll<T extends typeof Foo>(this: T): Array<InstanceType<T>> {
            return []
        }
    }
    
    class Bar extends Foo { }
    
    const a = Bar.getAll() // typeof a is Bar[]
    const b = Bar.create() // typeof b is Bar.
    

    我在链接的 GitHub 示例中放入 create 函数只是为了说明。

    【讨论】:

    • 哇,我一直在寻找这个答案很长一段时间。谢谢!
    • 静态 getter 的解决方案是什么,因为它不能带参数?
    • 这应该是公认的答案。谢谢
    • 这是对的。谢谢你。我同意,这应该是公认的答案。
    【解决方案3】:

    基于Brains answer,您可以直接使用返回类型

    (typeof Class)['foo']

    示例:

    export class MyClass {
        myFunction(param:string):number{
            return typeof param === "string"?1:0
        }
                                                 /** Just class['foo'] to normal methods */   
        static myStaticFunctions(cards: string): Parameters<MyClass['MyFunction']>[0] {
                            /** and *(typeof class)* ['foo'] to static methods */   
            const typedReturn: ReturnType<(typeof MyClass)['myStaticFunctions']> = "works"
            return typedReturn
            
        }
    }
    

    【讨论】:

      【解决方案4】:

      你期望这个静态方法在继承的子类中返回什么?是不是这样的:

      class A {
          private static _instances = new Array<A>();
          static instances(): A[] { return A._instances; }
          constructor() { A._instances.push(this); }
      }
      
      class B extends A {
      
          static instances(): B[] { 
              return <B[]>(A.instances().filter(i => i instanceof B)); 
          }
          constructor() { super(); }; 
      }
      
      var a = new A();
      var b = new B();
      
      console.log(
           "A count: " + A.instances().length + 
          " B count: " + B.instances().length);
      

      这将输出“A 计数:2 B 计数:1”。或者你期待什么?

      【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-11-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多