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

ehxuflar  于 2023-01-31  发布在  TypeScript
关注(0)|答案(5)|浏览(154)

我试图创建一个函数,它将参数传递给另一个函数。这两个函数需要有相同的重载。

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 "的参数。
类型"number"不能赋给类型"string"。(2345)input. tsx(4,10):对此实现的调用本应成功,但重载的实现签名对外部不可见。
Playground

vddsk6oq

vddsk6oq1#

你可以使用typeof操作符将你的pass函数声明为original函数的类型,例如。

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

let pass: typeof original =  () => {
  return true;
};

pass(5);         // all good
pass('a', 'b');  // all good
pass(45, 'b');   // error here

这里是Playground

ogsagwnx

ogsagwnx2#

添加额外过载:

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,但仍可以保留它以提高代码的可读性。
Playground

6tqwzwtp

6tqwzwtp3#

大多数情况下,函数重载的实现会接收到最松散的类型,“any”或“unknown”。但是“any”会使你丢失类型(所有相关变量都将变为“any”类型),所以“unknown”是唯一的选择。为什么实现会接收到最松散的类型?
你重载函数仅仅是因为你想让函数接受不同类型/数量的参数。但是,你怎么知道函数被调用时传入的参数的类型呢?你不知道,你必须先做一些类型检查。

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

function pass (a: number): boolean;
function pass (a: string, b: string): boolean;
function pass (a: unknown, b?: unknown): boolean {
  if(typeof a === "number" && typeof b === "undefined"){
    return original(a);
  }
  if(typeof a === "string" && typeof b ==="string"){
    return original(a, b)
  }
  return false; // maybe, depends on your logic 
}

由于实现函数的类型签名在外部不可见,因此您不会得到pass(unknown, unknown)签名,只会建议使用实现函数上面的两个签名。

dffbzjpn

dffbzjpn4#

这里有一个解决方案,它不使用类型Assert,也不更改或添加任何重载签名到任何函数:使用IIFE创建两个函数,其中函数在IIFE的“private”作用域内具有较弱的签名,但在作用域之外具有较强的签名。

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链接

xesrikrc

xesrikrc5#

在实现中向任何一个强制转换;)。对于重载签名,您可以确定除了允许的参数之外没有其他内容。

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);
}

相关问题