Próbuję utworzyć plik global.d.ts dla wektorowego libem matematyki. Istnieją pewne funkcje, które mogą podejmować różne zestawy argumentów. Na przykład:

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

A dokumenty to opisują jako

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

I zawsze zwraca obiekt wektorowy

Jak mogę zdefiniować taki typ lub interfejs, aby dopasować to zachowanie?

Próbowałem tego

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

I nie ma błędów, ale kiedy go używam

vector.add(2, 4)

Skarży się Argument of type '2' is not assignable to parameter of type 'number & Vec2 & [number, number]'

Czego mi brakuje? Należy pamiętać, że jest to trzeci lib i mogę pisać tylko dokładki i nie mogę dotknąć kodu LiB.

0
George 26 luty 2019, 17:20

2 odpowiedzi

Najlepsza odpowiedź

To, co zdefiniowałeś, jest związkiem sygnaturami funkcyjnymi. Jest to inne niż funkcja z przeciążeniami. Związek funkcji oznacza, że funkcja wykonawcza może mieć jedną z tych podpisów, ale nie wszystkie. Dlatego dzwoniąc do argumentów muszą być zgodne ze wszystkimi argumentami, ponieważ argument powinien być ważny dla jednej z możliwych funkcji, które można przypisać.

Składnia podpisu funkcji z przeciążeniami jest nieco inna:

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

Skrzyżowanie zamiast Unii będzie również działać jako przeciążony podpis:

type addFunction = (
    ((x: number, y: number, returnNew?: boolean) => Vec2) &
    ((vec: Vec2, returnNew?: boolean) => Vec2) &
    ((pos: [number, number], returnNew?: boolean) => Vec2)
)
2
Titian Cernicova-Dragomir 26 luty 2019, 14:23

Przeciążenie funkcji w pracach maszynopisowych, ale musisz sprawdzić, jakie przeciążenie jest używane ręcznie. Więc dla twojego przykładu ...

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
    }
}
0
Matěj Pokorný 26 luty 2019, 14:43