【发布时间】:2021-12-15 20:27:48
【问题描述】:
我尝试实现一个函数,该函数将扩展指定函数以具有 function composition 的可链接方法;如下;
{
const F = <T, U>(f: (a: T) => U) => {
type F = {
compose: <V, >(g: (b: U) => V) => (((a: T) => V) & F);
};
return Object.defineProperty(f, "compose", {
configurable: true,
value: <V,>(g: (b: U) => V) => F((a: T) => g(f(a)))
}) as ((a: T) => U) & F
};
//--------------------------------
const f1 = (a: number) => a + 1;
const f2 = (a: number) => a.toString();
const identity = <T,>(a: T) => a;
//--------------------------------
const F2 = F(f2);
// ((a: number) => string) & F // good
const F12 = F(f1).compose(f2);
// ((a: number) => string) & F // good
//--------------------------------
const F2i = (F2).compose(identity);
// ((a: number) => string) & F // good
const f12i = (F12).compose(identity);
// ((a: number) => number) & F // bad why??
//--------------------------------
const fi1 = F(identity).compose(f1);
/* ts(2345) error
Argument of type '(a: number) => number' is not assignable to parameter of type '(b: unknown) => number'.
Types of parameters 'a' and 'b' are incompatible.
Type 'unknown' is not assignable to type 'number'.
const f1: (a: number) => number
*/
}
在这个示例代码中,我们有 3 个基本功能; f1、f2 和 identity。
F是一个函数,就是将一个指定的函数扩展成一个函数组合的方法。
我设法让它工作了;但是我发现至少有 2 个问题。
1.
现在,我们将F 用于f2,而F2 的类型是((a: number) => string) & F,这是意料之中的。
那么,我们用F代替f1,用f2组合,F12的类型也是((a: number) => string) & F,这是意料之中的。
因此,F2 和 F12 的类型是相同的,到目前为止,很好。
现在,(F2).compose(identity) 的类型应该是 ((a: number) => string) & F。
但是,(F12).compose(identity) 的类型是 ((a: number) => number) & F,这是意料之中的。
我已经跟踪我的代码很长时间了,但我不知道为什么会发生这种情况。
你能给我建议吗?谢谢!
编辑:
请注意函数不应该被包裹在Object中,我的意图是直接为函数提供一个compose方法:
const f = (a: number) => a + 1;
const fg = f.compose(g);
//not
{
f: f,
compose:someFunction
}
编辑:对于第二个问题,@jcalz 的 cmets,我创建了单独的问题:
Is there any workaround for ts(2345) error for TypeScript lacks higher kinded types?
2.
如图所示,我有 ts(2345) 错误,错误消息对我来说没有意义,所以我不知道如何解决这个问题。
【问题讨论】:
-
我意识到问题是关于推理的,但是显式传递泛型有什么问题?
const fi1 = F<number, number>(identity).compose(f1);类型检查就好了.... -
您的两个问题应该是两个独立的问题。您的第一个问题是您定义
F的compose()方法以返回与自身相同的类型F,这意味着链中的每个后续链接仍将期望回调采用原始U类型。如果你想正确地进行链接,你需要改用this 之类的东西。 -
您的第二个问题是 TypeScript 缺少表达您想要做的事情所需的更高种类的类型;尽管有一些 support 用于类似的操作,但您不能在此处使用返回的通用函数来执行此操作,该函数还具有其他属性。所以这是不可能的,你需要手动指定参数。
-
问题是:这两件事中的哪一件是您真正的问题?我很乐意回答其中一个问题,但将两者联系在一起的唯一原因是您使用相同的代码遇到了这两个问题。如果你对一件事提出这个问题,我会用一个解释来回答它。您应该随时就另一件事提出单独的问题。
-
@jcalz 感谢您每次的输入,您总是大大改进了我的代码!真的很感激..那么,很明显,你已经在你的第一条评论中用操场代码解决了我的#1问题,所以我想要求回答#2的问题。谢谢!
标签: typescript function functional-programming function-composition