【问题标题】:How to have functions pass arguments with the same overloads?如何让函数传递具有相同重载的参数?
【发布时间】:2021-03-14 13:42:20
【问题描述】:

我正在尝试创建一个函数,将其参数传递给另一个函数。这两个函数都需要有相同的重载。

function original (a: number): boolean;
function original (a: string, b: string): boolean;
function original (a: number | string, b?: string): boolean {
  return true;
}

function pass (a: number): boolean;
function pass (a: string, b: string): boolean;
function pass (a: number | string, b?: string): boolean {
  return original(a, b);
}

这不起作用。

'string | 类型的参数number' 不能分配给 'string' 类型的参数。

类型“数字”不可分配给类型“字符串”。(2345) input.tsx(4, 10):调用会成功针对此实现,但重载的实现签名在外部不可见。

Playground

【问题讨论】:

  • 你不能。您必须将 original 的内部类型公开为重载。
  • 请记住,一旦你重载了original 函数,这个类型签名function original (a: number | string, b?: string): boolean(最后一个)就不会暴露给外部世界。你可以考虑复制这个function original (a: number | string, b?: string): boolean 就像这里tsplay.dev/mqQy2m

标签: typescript overloading


【解决方案1】:

添加额外的重载:

function original<
  A extends number | string,
  B extends A extends string ? string : undefined
>(a: A, b: B): boolean;

现在看起来像:

function original(a: number): boolean;
function original(a: string, b: string): boolean;

function original<
  A extends number | string,
  B extends A extends string ? string : undefined
>(a: A, b: B): boolean;

function original(a: number | string, b?: string): boolean {
  return true;
}

function pass(a: number): boolean;
function pass(a: string, b: string): boolean;
function pass(a: number | string, b?: string): boolean {
  return original(a, b); // Works
}

const t1 = original(1); // Works
const t2 = original("foo", "foo"); // Works
const t3 = original(1, "foo"); // Works: gives an error as expected
const t4 = original("foo"); // Works: gives an error as expected

您不再需要第二个重载function original(a: string, b: string): boolean,但您仍可以保留它以提高代码的可读性。

Playgroun

【讨论】:

    【解决方案2】:

    这是一个不使用类型断言并且不更改或添加任何重载签名到任一函数的解决方案:使用IIFE 创建两个函数,其中函数在 IIFE 的“私有”中具有较弱的签名范围,但外部签名更强。

    interface OriginalSignature {
      (a: number): boolean;
      (a: string, b: string): boolean;
    }
    
    const [original, pass] = (function(): [OriginalSignature, OriginalSignature] {
      function original(a: number | string, b?: string): boolean {
        return true;
      }
      function pass(a: number | string, b?: string): boolean {
        return original(a, b);
      }
      return [original, pass];
    })();
    

    测试:

    // OK
    original(1);
    original('a', 'b');
    pass(1);
    pass('a', 'b');
    
    // errors
    original('a');
    original(1, 'b');
    pass('a');
    pass(1, 'b');
    

    Playground Link

    【讨论】:

      【解决方案3】:

      强制转换为任何实现;)。使用重载的签名,您可以确定除了允许的参数之外别无其他。

      function original (a: number): boolean;
      function original (a: string, b: string): boolean;
      function original (a: number | string, b?: string): boolean {
        return true;
      }
      
      function pass (a: number): boolean;
      function pass (a: string, b: string): boolean;
      function pass (a: number | string, b?: string): boolean {
          return original(a as any, b as any); // here, you are sure only 
          // expected arguments may appear - so the cast operation is safe.
      }
      

      或者使用命名元组而不是重载(效果类似于重载)。

      function original(...args: [a: string, b: string] | [a: number]): boolean {
        return true;
      }
      
      function pass (...args: [a: string, b: string] | [a: number]): boolean {
        return original(...args);
      }
      

      【讨论】:

      • 我不得不使用这个解决方法,直到我发现我的过载问题:P
      猜你喜欢
      • 2012-06-05
      • 2018-02-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2015-01-14
      • 1970-01-01
      相关资源
      最近更新 更多