网站搜索

typescript - 我可以将映射元组类型用于 juxt 函数吗?


juxt 调用一组函数以返回一组值。文档:ramda clojure

我正在尝试编写这个的以数据为先的版本,不使用覆盖,但我无法弄清楚如何将函数元组映射到它们的返回值。这是我现在的写法:

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

它抱怨(以及其他抱怨)

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

在 TypeScript 中这是可能的吗?

答案#1

考虑在这种情况下使用函数重载:

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)]
)

操场

我添加了条件类型 Fns[K] extends Fn ? ReturnType<Fns[K]> : never 只是为了确保 TypeScript 知道 Fns[K] 是一个函数

你可以在这里找到关于推断 [].map 返回类型的更多信息。这一更改曾被合并,然后又被撤回。

为了更好地理解这个语法 [...Fns],请参阅可变元组类型的文档

答案#2

我不确定为什么 ReturnType 不起作用。不过,这里有一个替代方法:

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}

这里是完整的游乐场。那有帮助吗?