如何在打字稿中正确重载具有多个参数的函数?

How to overload a function with multiple parameters correctly in typescript?

我正在尝试定义一个适用于数组和字符串的函数 includes

但我无法正确输入它。如果我理解正确,可以使用联合重载。所以这就是我正在尝试的:

// Declarations
export function includes<T>(arr: T[], el: T): boolean;
export function includes(str: string, substr: string): boolean;
// Implementation
export function includes<T>(arr: T[] | string, el: T | string) {
  return arr.indexOf(el) !== -1;
}

但我收到错误消息:

'string' is assignable to the constraint of type 'T', but 'T' could be instantiated with a different subtype

这是有道理的,因为如果 arrT 类型,el 不应该是 string 类型,但是联合使得 "possibility".

那么我如何在此处正确键入实现以说明参数可能是 T[] and Tstring and string

调用 arr.indexOf(el) 是不安全的,其中 arrT | string[] 并且 elT | string 因为编译器不确定你是不匹配它们,如 "typescript".indexOf(2)[1,2,3].indexOf("rip")arrel 的类型应该 correlated 这一事实很难在 TypeScript 中表达。在没有 correlated record types (see microsoft/TypeScript#30581)] 的情况下,在实现中使用 any 或其他变通方法等类型安全性较低的事情是合理的,因为重载调用签名可以防止任何此类不健全对您的调用者可见功能。

但是,对于您的情况,我倾向于使用以下实现签名:

export function includes<T>(arr: { indexOf(x: T): number }, el: T) {
    return arr.indexOf(el) !== -1;
}

在这里,我们只关心 arr 有一个 indexOf() 方法,它接受某种类型的值 T 和 returns a number,而 elT。这使得 arr.indexOf(el) 无论如何都可以毫无错误地编译,并且它与两个重载调用签名兼容。事实上,您甚至可能想要放弃重载并只使用上面的定义,除非您有某种理由将 includes() 限制为 string-or-Array<T> 输入。让我们确保它的行为:

includes("typescript", "rip"); // okay
includes([1, 2, 3], 2); // okay

includes("typescript", 2); // error
includes([1, 2, 3], "rip"); // error

我觉得不错。希望有所帮助;祝你好运!

Link to code