【问题标题】:TypeScript child class: how to set argument type and return type of method defined in the parent classTypeScript 子类:如何设置父类中定义的方法的参数类型和返回类型
【发布时间】:2020-10-01 13:33:21
【问题描述】:

我有一个父类,它需要子类来实现自定义businesslogic() 方法。有不止一个子类,每个子类对应的businesslogic()方法都有不同的类型签名。

父类中有一个通用方法:它的返回值取决于子类的businesslogic()实现。

我确实希望这段代码能证明这一点:

abstract class Parent {
  protected name: string;

  constructor(name: string) {
    this.name = name;
  }

  protected abstract businesslogic(params?: unknown): unknown;

  public setup(params?: unknown): unknown {
    // business logic involving `params`
    const foo = this.businesslogic(params);
    // do something with the result of the business logic
    console.log(foo);
    // and then return it
    return foo;
  }
}

class Child1 extends Parent {
  businesslogic(c: number): number {
    return c + 1;
  }
}

class Child2 extends Parent {
  businesslogic(c: string): string {
    return c;
  }
}

const c1 = new Child1("Mirco");
c1.setup(1);

const c2 = new Child2("Isolde");
c2.setup("a");

在这个例子中,这两个子类都实现了一个自定义的businesslogic()——在类型签名方面有所不同。

tsc 似乎将c1.setup(1) 与一般签名Parent.setup(params?: unknown): unknown 进行比较——这是有效的。但我现在正在寻找一种更好的方法,在调用子类的 setup() 方法时,我可以在子类的声明中稍微“覆盖”setup(params?: unknown): unknown 的类型签名,以实现更强的类型约束。

也就是说,我确实相信以下是我想要的:在子类声明中,我想覆盖父类中公共方法的类型签名。 (如何)这可能吗?

我也很欣赏这类问题的更优雅解决方案的指针!

【问题讨论】:

    标签: typescript typescript-typings


    【解决方案1】:

    可能有几种方法可以设计和键入这些关系,这里有一种使用泛型和 Typescript 4 新的可变参数元组类型的方法。您将业务逻辑函数参数和返回类型指定为传递给 Parent 类的泛型类型。

    将错误的参数类型传递给setup 或尝试将其返回值分配给不同的类型将无法编译。

    abstract class Parent<T extends unknown[], U> {
      protected name: string;
    
      constructor(name: string) {
        this.name = name;
      }
    
      protected abstract businesslogic(...params: [...T]): U;
    
      public setup(...params: [...T]): U {
        // business logic involving `params`
        const foo = this.businesslogic(...params);
        // do something with the result of the business logic
        console.log(foo);
        // and then return it
        return foo;
      }
    }
    
    class Child1 extends Parent<[number], number> {
      businesslogic(c: number): number {
        return c + 1;
      }
    }
    
    class Child2 extends Parent<[string], string> {
      businesslogic(c: string): string {
        return c;
      }
    }
    
    class Child3 extends Parent<[number, string], string> {
      businesslogic(x: number, c: string): string {
        return x + 1 + c;
      }
    }
    
    class Child4 extends Parent<[], string> {
      businesslogic(): string {
        return "";
      }
    }
    
    const c1 = new Child1("Mirco");
    // r1 is a number
    const r1 = c1.setup(1);
    
    const c2 = new Child2("Isolde");
    // r2 is a string
    const r2 = c2.setup("a");
    
    const c3 = new Child3("Another one");
    // Child3 expects 2 parameters for setup
    // r3 is a string
    const r3 = c3.setup(1, "a");
    
    const c4 = new Child4("Yet another");
    // Child4 expects no parameters for setup
    const r4 = c4.setup();
    

    【讨论】:

    • 感谢您通过@danielv 思考这个问题!毕竟我没有使用可变元组类型,但可以使用一些更简单的东西——但这当然是一个可爱的通用答案,它完全为我指明了正确的方向!我还了解到,默认为 void 的通用可选类型可用于 not 根本不需要参数,但是当子类将其覆盖为 void 以外的其他参数时,它就成为必需的参数:stackoverflow.com/a/62280834/145400
    猜你喜欢
    • 2021-07-28
    • 2021-04-05
    • 2014-11-25
    • 2022-11-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-03-18
    相关资源
    最近更新 更多