Как определить несколько типов для rest parameters?

TypeScript.
Есть некоторый класс.
Метод something(...) может принимать несколько аргументов, и это известно до создания экземпляра.

// Тип "T" должен описать последовательность типов метода something
class Foo<T> {

  #callback: (...args: T[]) => void

  constructor(callback: (...args: T[]) => void) {
    this.#callback = callback
  }

  // Как быть с параметрами (a: number, b:string)
  something(...args: T[]): void {
    this.#callback(...args)
  }
}

// Здесь уже известно какие параметры будет принимать метод `Foo.something(...)`,
// и соответственно какие получит `callback`.
const callback = (a: number, b: string): void => {
  // ...
}

// Это разумеется не сработает, даже callback не будет соответствовать ожидаемому типу
const cfoo = new Foo<(number | string)>(callback)
cfoo.something(123, 'str')

Playground

Возможно ли в rest parameters определить несколько типов, соблюдая установленную последовательность?


Ответы (1 шт):

Автор решения: Alexander Lonberg

Оказалось это делается с помощью кортежей.
Тип кортежа описывается как:

T extends any[]

Вот так все работает:

class Foo<T extends any[]> {

  #callback: (...args: T) => void

  constructor(callback: (...args: T) => void) {
    this.#callback = callback
  }

  something(...args: T): void {
    this.#callback(...args)
  }
}

const callback = (a?: number, b?: string): void => {
  // ...
}

const cfoo = new Foo<[number?, string?]>(callback)
cfoo.something(123, 'str')
cfoo.something('error string', 'str')
// -------------^^^^^^^^^^^^ - error

Playground

→ Ссылка