如何让这个reduce函数返回类型Set<1>? (游乐场)
const toSet = <const V>(acc=new Set<V>(),v:V) =>{
acc.add(v);
return acc;
}
const set = toSet(undefined,1); // Set<1> correct
const reduce =
<NextReducer extends (acc:any,value:any)=>any>(nextReducer:NextReducer) =>
(acc: unknown, value: unknown) =>
nextReducer(acc, value);
const reduced = reduce(toSet)(undefined,1); // any (should be Set<1>)
TypeScript 对“从泛型函数进行高阶类型推断”的支持仅在特定的有限情况下有效,如 microsoft/TypeScript#30215 中实现的那样。 一项要求是高阶函数需要在其输入函数的参数和返回类型中单独是通用,并且在整个输入函数类型中不是通用的。 意味着您不能像您在问题中所写的那样写
<F extends (acc:any,value:any)=>any>(nextReducer: F)=>⋯
。 相反,您需要写类似
<A, V, R>(nextReducer: (acc: A, value: V) => R)=>⋯
的内容。这将为您提供以下版本的 reduce
:const reduce =
<A, V, R>(nextReducer: (acc: A, v: V) => R) =>
(acc: A, value: V) => nextReducer(acc, value);
reduce
的结果类型是
<A, V, R>(f: (a: A, v: V) => R) => (a: A, v: V) => R
。这比您的版本更安全,因为返回的函数不应具有像 (acc: unknown, value: unknown)
这样的参数,因为
nextReducer
可能不接受 unknown
参数。 (例如,没有什么可以阻止某人调用 reduce(toSet)("oops", "darn")
并在 "oops".add("darn")
上收到运行时错误)而且,对于你的问题更重要的是,这允许高阶类型推断起作用:
const reduceToSet = reduce(toSet);
// const reduceToSet: <const V>(acc: Set<V> | undefined, value: V) => Set<V>
您可以看到
reduce(toSet)
保留了
toSet
的泛型。这样你就得到了想要的行为:const reduced = reduce(toSet)(undefined, 1);
// const reduce: Set<1>
这就是所问问题的答案。
请注意,如果您实际上打算尝试将
reduce
转换为真正的
归约操作(对数组或树等递归数据结构进行操作),您可能会发现这更复杂并且保存/传播仿制药可能会更困难,甚至不可能。但这超出了所问问题的范围。 Playground 代码链接