【发布时间】:2019-01-22 09:00:59
【问题描述】:
TypeScript 3.0 引入generic rest parameters。
到目前为止,curry 函数必须在 TypeScript 中使用 finite number of function overloads 和一系列查询实现中传递参数数量的条件语句进行注释。
我希望通用休息参数最终提供实现完全通用解决方案所需的机制。
我想知道如何使用这个新的语言特性来编写一个通用的curry 函数……当然可以假设!
使用我从solution I found on hackernoon 稍微修改的其余参数的 JS 实现看起来像这样:
function curry(fn) {
return (...args) => {
if (args.length === 0) {
throw new Error("Empty invocation")
} else if (args.length < fn.length) {
return curry(fn.bind(null, ...args))
} else {
return fn(...args)
}
}
}
使用通用的 rest 参数和函数重载,我在 TypeScript 中注释这个 curry 函数的尝试如下所示:
interface CurriedFunction<T extends any[], R> {
(...args: T): void // Function that throws error when zero args are passed
(...args: T): CurriedFunction<T, R> // Partially applied function
(...args: T): R // Fully applied function
}
function curry<T extends any[], R>(
fn: CurriedFunction<T, R>
): CurriedFunction<T, R> {
return (...args: T) => {
if (args.length === 0) {
throw new Error("Empty invocation")
} else if (args.length < fn.length) {
return curry(fn.bind(null, ...args))
} else {
return fn(...args)
}
}
}
但是 TypeScript 会抛出错误:
Type 'CurriedFunction<any[], {}>' is not assignable to type 'CurriedFunction<T, R>'.
Type '{}' is not assignable to type 'R'.
我不明白R 在哪里以及为什么被推断为{}?
【问题讨论】:
-
不确定
CurriedFunction类型 args 的柯里化应该如何发生,因为T参数到CurriedFunction在输入和输出中总是相同的 -
你是对的。我有一种感觉,我需要另一个从
any[]扩展的通用变量来注释返回的 curried 函数的参数。 -
强类型
bind()在 TypeScript 3.0 中仍然不可能,因为在类型系统中没有(支持的)concatenate tuples 方法。所以你可能不会轻易做到这一点。 -
@jcalz 连接是不可能的我同意,但是删除第一个参数(或前 n 个参数)应该是可能的,这对于 bind 还不够吗? (顺便说一句:恭喜你获得金牌 :))
-
不可能删除泛型 n 的前 n 个参数,这是需要的。你仍然可以做大量的重载或偷偷摸摸的编译器恶意递归,但这不是很好。
标签: typescript generics currying typescript3.0