【问题标题】:How to return subtype from superclass method instead of superclass type如何从超类方法返回子类型而不是超类类型
【发布时间】:2018-05-09 11:39:13
【问题描述】:

我认为这是正确实现泛型的问题,但我不确定。

我创建了一个 Github gist 来代表这里的问题: https://gist.github.com/ORESoftware/66b72b4b85262d957cb03ad097e4743e

假设我有这个超类:

  class A {

    foo(): A {
      return this;
    }

  }

还有几个子类,例如一个看起来像这样:

   class B extends A {

     bar(): B {
      return this;
     }

   }

如果我这样做了

new B().foo().bar()

这将在运行时工作,但它不能使用 TypeScript 编译。这是因为foo() 声明返回类型为A,而不是类型B

如何返回 this 的类型,而不是声明 foo() 始终返回类型 A

我试过这个:

但我收到此错误:

【问题讨论】:

    标签: typescript generics typescript2.0 typescript-generics


    【解决方案1】:

    您必须使用polymorphic this type 返回this 的类型。

    abstract class A {
        foo(): this {
            return this;
        }
    }
    
    class B extends A {
        bar(): this {
            return this;
        }
    }
    

    这将允许

    const b = new B();
    
    b.foo().bar();
    

    【讨论】:

    • 有没有办法返回this的新实例?
    • @DAnsermino 如果你愿意的话。您可以在B::bar 中执行return new B as this
    • 我怎样才能为静态方法做到这一点? static foo(obj:<SubClass>):<SubClass>{ return obj; }this 类型不能在静态上下文中使用。
    【解决方案2】:

    我有两个例子给你,一个是重载的,一个是泛型​​接口的。

    重载

    如果您打算让new C().foo().zoom() 版本工作,您可以实现这一点,同时仍然会收到有关以下代码的bar() 错误的警告,这会创建一个兼容的重载,该重载返回该类型的子类型父类:

    class A {
      foo(): A {
        return this;
      }
    }
    
    class B extends A {
      foo(): B {
        return this;
      }
    
      bar(): B {
        return this;
      }
    }
    
    class C extends A {
      foo(): C {
        return this;
      }
    
      zoom(): C {
        return this;
      }
    }
    
    const result = new C().foo().zoom();
    

    如果您的代码中的真实方法确实做了您想要重用的事情,您可以调用 super.foo()... 但在示例代码中不需要。

      foo(): C {
        const a = super.foo();
        // You still need to return this, as it is a C, not an A.
        return this;
      }
    

    泛型

    您不能将基类设为泛型,以返回类型T。您不能将类用作其自身类型参数的类型约束。您还有一个问题,A 不能保证与扩展 AT 兼容。

    可以做的是引入一个接口,并在每个类上使用它:

    interface Fooable<T> {
      foo(): T;
    }
    
    class A {
      foo(): any {
        return this;
      }
    }
    
    class B extends A implements Fooable<C> {
      bar(): B {
        return this;
      }
    }
    
    class C extends A implements Fooable<C> {
      zoom(): C {
        return this;
      }
    }
    
    const result = new C().foo().zoom();
    

    【讨论】:

    • 不是这样,问题是foo() 声明它的返回类型为A foo(): A,但我需要它是this 的任何类型,这很可能到BC,而不是A
    • 我在问题中犯了一个错误,我更正了 - 我的意思是new B(),而不是new C()
    • 我会让A 成为一个通用类来解决这个问题,但是要正确地做到这一点,你需要有class A&lt;T extends A&gt; 并且你不能使用一个类作为它的类型约束自己的泛型类型参数。
    • 我创建了一个 Github gist,并将链接放在问题中,您可以将 gist 复制到 .ts 文件中,您将看到问题。
    • 很抱歉问这个问题,但我改进了这个问题,最初问题中的一个错误导致您回答的问题与预期不同,请按照您现在认为合适的方式更新答案。
    猜你喜欢
    • 1970-01-01
    • 2013-10-17
    • 1970-01-01
    • 2013-04-14
    • 1970-01-01
    • 2018-12-28
    • 1970-01-01
    • 1970-01-01
    • 2011-04-05
    相关资源
    最近更新 更多