【问题标题】:Typescript function overload depending on interface genericTypescript函数重载取决于接口泛型
【发布时间】:2022-01-26 03:14:36
【问题描述】:

如果类泛型属于某种类型,有没有办法用可选参数声明方法重载?在下面的示例中,目标是只有当类的泛型 T 是数字时,其 run 方法才需要参数。我写的东西不起作用:我认为run 声明中的T 被解释为与Test 的通用T 不同的通用。有没有办法做到这一点?


class Test<T extends string | number> {
  run<T extends number>(a: number): void
  run<T extends string>(a?: number): void
  run(a: number): void {
    console.log(a)
  }
}

const a = new Test<number>();
a.run() // This should be an error, as a's generic is a number and thus its run method should require an argument.

const b = new Test<string>();
b.run() // OK, since b's generic is a string.

【问题讨论】:

    标签: typescript typescript-generics


    【解决方案1】:

    我一直在尝试找到一种仅使用一个类来完成此任务的方法,但我不确定这是否可能。这是有道理的,因为以不同的方式调用相同的函数并不是很干净

    你可以做的是使用一个接口,一个父类和多个子类。这将允许您使用其中一种,同时保持干燥。这是我对这个问题的看法。

    // we create an interface with an optional parameter "a"
    interface ITest {
      run(a?: number) : void;
    }
    
    // we create a super class that will handle the process of the "run" function.
    // this class has a function with a necessary parameter
    abstract class AbstractTest<T extends string|number> {
      run(a: T) {
        console.log('ran with param: ', a);
      }
    }
    
    // We create two sub class, one for the run with no parameter, one with the run with one parameter. 
    // Both classes implements the interface and calls the parent function "run".
    
    // this class does not extends the "run" function, since it is the same as the parent one
    class TestNumber<T extends number> extends AbstractTest<T> implements ITest {}
    
    // this class extends the "run" function, since it needs to process the fact that there is no parameters passsed
    // to the "run" function. I've used a default value here, but it will depend on your use case.
    class TestString<T extends string> extends AbstractTest<T> implements ITest {
      public static readonly DEFAULT_VALUE = 'some value';
    
      run() : void {
        super.run(TestString.DEFAULT_VALUE as T)
      }
    }
    
    // we create new objects based on the need.
    const a = new TestNumber<number>();
    const b = new TestString<string>();
    
    // this function call works since we've passed a parameter
    a.run(42);
    // this one does not work and an error is thrown.
    a.run()
    
    // this function call works great without an argument.
    b.run()
    

    我已经放置了 cmets 来解释这些变化。 here is a typescript playground 带有工作代码

    【讨论】:

      【解决方案2】:

      在这种情况下,conditionally-typed rest parameter 是您的方法的有用选择:

      TS Playground

      class Test <T extends string | number> {
        run (...args: T extends number ? [a: number] : [a?: number]): void {
          const [a] = args;
          console.log(a); // number | undefined
        }
      }
      
      const a = new Test<number>();
      a.run(42); // ok
      a.run(); /*
        ^^^^^
      Expected 1 arguments, but got 0.(2554) */
      
      const b = new Test<string>();
      b.run(42); // ok
      b.run(); // ok
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2018-09-15
        • 1970-01-01
        • 2021-04-23
        • 2017-07-22
        • 2020-11-15
        • 1970-01-01
        • 2021-09-16
        相关资源
        最近更新 更多