定义带有重载的函数的类型

时间:2019-02-26 14:20:02

标签: typescript typescript-typings

我正在尝试为我正在使用的矢量数学库创建一个global.d.ts文件。有一些函数可以采用不同的参数集。例如:

function add(x, y, returnNew) {
  if (typeof x != 'number') {
    returnNew = y;
    if (isArray(x)) {
      y = x[1];
      x = x[0];
    } else {
      y = x.y;
      x = x.x;
    }
  }

  x += this.x;
  y += this.y;


  if (!returnNew) {
    return this.set(x, y);
  } else {
    // Return a new vector if `returnNew` is truthy
    return new (this.constructor)(x, y);
  }
}

和文档将其描述为

add(x, y [, returnNew]) or
add(array, [, returnNew]) or
add(vec2 [, returnNew])

它总是返回一个矢量对象

如何定义这种类型或接口以匹配此行为?

我尝试过

type addFunction = (
    ((x: number, y: number, returnNew?: boolean) => Vec2) |
    ((vec: Vec2, returnNew?: boolean) => Vec2) |
    ((pos: [number, number], returnNew?: boolean) => Vec2)
)

并且没有错误,但是当我使用它

vector.add(2, 4)

它抱怨Argument of type '2' is not assignable to parameter of type 'number & Vec2 & [number, number]'

我想念什么?请注意,这是第三方库,我只能输入内容,不能触摸库代码。

2 个答案:

答案 0 :(得分:2)

您定义的是函数签名的并集。这与带有重载的函数不同。函数的并集意味着实现的函数可以具有这些签名中的任何一个,但不能具有全部签名。这就是为什么在调用参数时必须与所有参数兼容的原因,因为该参数对于任何可能分配的功能都应该有效。

带有重载的函数签名的语法略有不同:

type addFunction = {
    (x: number, y: number, returnNew?: boolean): Vec2
    (vec: Vec2, returnNew?: boolean): Vec2
    (pos: [number, number], returnNew?: boolean): Vec2
}

相交而不是并集也将充当重载签名:

type addFunction = (
    ((x: number, y: number, returnNew?: boolean) => Vec2) &
    ((vec: Vec2, returnNew?: boolean) => Vec2) &
    ((pos: [number, number], returnNew?: boolean) => Vec2)
)

答案 1 :(得分:0)

Typescript中的函数重载有效,但是您必须检查手动使用了哪些重载。因此,以您的示例为例...

function add(array: [number, number], returnNew?: boolean);
function add(vec2: { x: number, y: number }, returnNew?: boolean)
function add(x: number, y: number, returnNew?: boolean);
function add(
    param1: [number, number] | { x: number, y: number } | number,
    param2?: number | boolean,
    param3?: boolean) {
    if (Array.isArray(param1)) {
        // overload 1
    }
    else if (typeof param1 === 'object') {
        // overload 2
    }
    else {
        // overload 3
    }
}