TypeScript:继承类中静态方法的自引用返回类型

Posted

技术标签:

【中文标题】TypeScript:继承类中静态方法的自引用返回类型【英文标题】:TypeScript: self-referencing return type for static methods in inheriting classes 【发布时间】: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

【问题讨论】:

【参考方案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-generics 和 https://***.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 answer 到GitHub 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”。或者你期待什么?

【讨论】:

他希望他的getAll() 方法返回子类型的数组,而不必重新定义子类中的方法。见***.com/a/42768627/1268016

以上是关于TypeScript:继承类中静态方法的自引用返回类型的主要内容,如果未能解决你的问题,请参考以下文章

Typescript中的类

TypeScript教程# 10:继承简介

重载和重写的区别

java中在一个类中定义的一个静态方法,怎么引用时可以直接用,不用对象.方法,也不用类.方法?

TypeScript静态方法继承

使用数据注释和代码的自定义验证属性