Empresas
Empleos
  • Sobre nosotros
  • Soluciones
    • Publicación de vacantes
      Publica tu vacante y recibe candidatos calificados en 48h.
    • Evaluación de candidatos
      500+ pruebas técnicas y psicológicas, más anti-fraude.
    • Headhunting
      Búsqueda ejecutiva a la medida de principio a fin.
    • Nómina + EOR
      Dispersión de nómina y EOR en más de 15 países de LATAM.
  • Precios
  • Empleos

0

240
Vistas
TypeScript: Is it possible to define a variadic function that accepts different types of arguments?

I want to write a generic function that accepts variable number of arguments that may have different types and returns a tuple based on those arguments.

Here is an example in JavaScript:

function evaluate (...fns) {
  return fns.map(fn => fn())
}

evaluate(
  () => 10
) // [ 10 ]

evaluate(
  () => 10,
  () => 'f',
  () => null
) // [ 10, 'f', null ]

And in TypeScript I need to somehow convert the spread argument tuple to a resulting one:

function evaluate<T1, T2 ... Tn> (
  ...fns: [() => T1, () => T2 ... () => Tn]
): [T1, T2 ... Tn] {
  return fns.map(fn => fn()) as [T1, T2 ... Tn]
}

evaluate(
  () => 10
) // [ 10 ]: [number]

evaluate(
  () => 10,
  () => 'f',
  () => null
) // [ 10, 'f', null ]: [number, string, null]

I've tried a naive approach of creating an overload for all reasonable lengths of tuple:

function evaluate<T1> (
  fn1: () => T1
): [T1]
function evaluate<T1, T2> (
  fn1: () => T1,
  fn2: () => T2
): [T1, T2]
function evaluate<T1, T2, T3> (
  fn1: () => T1,
  fn2: () => T2,
  fn3: () => T3
): [T1, T2, T3]
function evaluate<T1, T2, T3> (
  ...fns: Array<(() => T1) | (() => T2) | (() => T3)>
): [T1] | [T1, T2] | [T1, T2, T3] {
  return fns.map(fn => fn()) as [T1] | [T1, T2] | [T1, T2, T3]
}

But it looks horribly, doesn't scale well and causes issues with a more complex function body.

Is there any way this could be done dynamically? Thanks!

about 4 years ago · Juan Pablo Isaza
1 Respuestas
Responde la pregunta

0

The easiest way to implement this is to make evaluate() generic in its arraylike output type T (intended to be a tuple type), and then represent the fns rest parameter as a mapped type on T, noting that mapped array/tuple types are also array/tuple types:

function evaluate<T extends any[]>(
  ...fns: { [I in keyof T]: () => T[I] }
) {
  return fns.map(fn => fn()) as T;
}

Note that the type assertion as T is necessary because the compiler cannot see that fns.map(fn => fn()) will have the effect of converting an array/tuple of function types to the array/tuple of corresponding return types. See Mapping tuple-typed value to different tuple-typed value without casts for more information.

Because {[I in keyof T]: () => T[I]} is a homomorphic mapped type where we are mapping directly over keyof T (see What does "homomorphic mapped type" mean? for more information), the compiler is able to infer T from it (linked page is deprecated, but still accurate and no new page exists 🤷‍♂️).

Let's see it in action:

const x = evaluate(() => 10);
// const x: [number]

const y = evaluate(
  () => 10,
  () => 'f',
  () => null
)
// const y: [number, string, null]

Looks good. The compiler sees that x is of type [number] and y is of type [number, string, null]. It also behaves reasonably in cases where you pass in a rest argument of unknown order/length:

const fs = [() => "a", () => 3];
// const fs: ((() => string) | (() => number))[]

const z = evaluate(...fs);
// const z: (string | number)[]

Here fs is of the type Array<(()=>string) | (()=>number)>, and so z is of the analogous type Array<string | number>.

Playground link to code

about 4 years ago · Juan Pablo Isaza Denunciar
Responde la pregunta
Encuentra empleos remotos

¡Descubre la nueva forma de encontrar empleo!

Top de empleos
Top categorías de empleo
Empresas
Publicar vacante Precios Comercial
Legal
Términos y condiciones Política de privacidad
© 2026 PeakU Inc. All Rights Reserved.
Andres GPT
Recomiéndame algunas ofertas
Necesito ayuda