如何让函数传递具有相同重载的参数?

Posted

技术标签:

【中文标题】如何让函数传递具有相同重载的参数?【英文标题】: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 【参考方案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

以上是关于如何让函数传递具有相同重载的参数?的主要内容,如果未能解决你的问题,请参考以下文章

请简述重载和重写的区别

什么是 重载 ?为什么要重载?有何特点?

TypeScript 中的函数重载与使用联合类型

Java中重载和重写的区别

java中重载,继承,重写和多态的区别

重写和重载