Home > OS >  Can I used mapped tuple types for the juxt function?
Can I used mapped tuple types for the juxt function?

Time:12-06

juxt calls an array of functions to return an array of values. Docs: ramda clojure

I'm trying to type a data-first version of this without overrides, but I can't figure out how to map the tuple of functions to their return values. This is what I have:

type JuxtFn<T> = (x: T) => any
function juxt<T, Fs extends JuxtFn<T>[]>(
  x: T,
  fns: Fs,
): {[K in keyof Fs]: ReturnType<Fs[K]>} {
  return fns.map(fn => fn(x))
}

It complains (among other complaints)

Type 'Fs[K]' does not satisfy the constraint '(...args: any) => any'.

Is this possible in TypeScript?

CodePudding user response:

I'm not sure why the ReturnType isn't working. Here's an alternative, however:

type JuxtFn<T> = (x: T) => any
function juxt<T, FS extends readonly JuxtFn<T>[]>(
  x: T,
  fns: FS,
) {
  return fns.map(fn => fn(x)) as unknown as { [K in keyof FS]: FS[K] extends (x:any)=>infer X ? X : never}

Full playground here. Does that help?

CodePudding user response:

Consider using function overload for this case:

type JuxtFn<T> = (x: T) => any

function juxt<T, Fn extends JuxtFn<T>, Fns extends Fn[]>(
  x: T,
  fns: [...Fns],
): { [K in keyof Fns]: Fns[K] extends Fn ? ReturnType<Fns[K]> : never }
function juxt<T, Fs extends JuxtFn<T>[]>(
  x: T,
  fns: Fs,
) {
  return fns.map(fn => fn(x))
}

// [string[], Promise<number>]
const result = juxt(
  10,
  [(v: number) => ['s'], (v: number) => Promise.resolve(42)]
)

Playground

I have added conditional type Fns[K] extends Fn ? ReturnType<Fns[K]> : never just to assure TypeScript that Fns[K] is a function

You can find more information about infering return type of [].map here. This was merged and then reverted.

  • Related