In flow there is support for $Compose
functions (see recompose as example). However, I can't seem to find such a mechanism in typescript. it seems that the best typescript can do is something like https://github.com/reactjs/redux/blob/master/index.d.ts#L416-L460. What's the equivalent to $Compose
in Typescript?
编辑:我尝试完成的是从recompose
或redux
中输入compose
函数,使其类型安全,特别是,对于react高阶组件,我想确保一个HOC的输出属性满足下一个HOC的输入属性。这是我目前的工作方法,似乎工作得相当好-尽管我希望有一个很好的方法在 typescript 中原生地完成这一点。
/** Wraps recompose.compose in a type-safe way */
function composeHOCs<OProps, I1, IProps>(
f1: InferableComponentEnhancerWithProps<I1, OProps>,
f2: InferableComponentEnhancerWithProps<IProps, I1>,
): ComponentEnhancer<IProps, OProps>
function composeHOCs<OProps, I1, I2, IProps>(
f1: InferableComponentEnhancerWithProps<I1, OProps>,
f2: InferableComponentEnhancerWithProps<I2, I1>,
f3: InferableComponentEnhancerWithProps<IProps, I2>,
): ComponentEnhancer<IProps, OProps>
function composeHOCs<OProps, I1, I2, I3, IProps>(
f1: InferableComponentEnhancerWithProps<I1, OProps>,
f2: InferableComponentEnhancerWithProps<I2, I1>,
f3: InferableComponentEnhancerWithProps<I3, I2>,
f4: InferableComponentEnhancerWithProps<IProps, I3>,
): ComponentEnhancer<IProps, OProps>
function composeHOCs(
...fns: Array<InferableComponentEnhancerWithProps<any, any>>
): ComponentEnhancer<any, any> {
return compose(...fns)
}
6条答案
按热度按时间ss2ws0br1#
我把你的问题解读如下:
我如何给予这个高阶函数一个TS类型,这样
x
的类型就可以在循环中变化?坏消息是你不能直接输入这个函数,
funs
数组就是问题所在--给予compose
一个最通用的类型,funs
应该是一个 * 类型对齐 * 的函数列表-每个函数的输出必须与下一个函数的输入匹配。TypeScript的数组是同构类型的-funs
的每个元素必须具有完全相同的类型-因此您不能直接在TypeScript中表达类型在整个列表中变化的方式。(上面的JS在运行时工作,因为类型被擦除,数据被统一表示。)这就是Flow的$Compose
是一个特殊的内置类型的原因。解决此问题的一个方法是执行您在示例中所做的操作:使用不同数量的参数为
compose
声明一组重载。很明显,这是不可伸缩的,你必须停下来,如果你的用户需要编写比你预期的更多的函数,那他们就惨了。
另一种选择是重写代码,以便一次只组合一个函数:
这相当混乱了调用代码--您现在必须编写单词
compose
及其伴随的括号,O(n)次。像这样的函数组合管道在函数语言中很常见,那么程序员如何避免这种语法上的不适呢?例如,在Scala中,
compose
是一个 * 中缀 * 函数,这使得嵌套的括号更少。在 haskell 语中,
compose
拼写为(.)
,这使得句子非常简洁:事实上,你可以在TS中组装一个中缀
compose
,其思想是用一个执行组合的方法将底层函数 Package 在一个对象中,你可以将该方法称为compose
,但我将其称为_
,因为它的噪音较小。仍然没有
compose(f, g, h, k)
那么整洁,但它也不太可怕,而且它比编写大量重载更好地扩展。toe950272#
从Typescript 4开始,可变元组类型提供了一种组合函数的方法,函数的签名可以从任意数量的输入函数中推断出来。
然而,这种实现方式仍然存在两个缺点:
1.编译器无法验证每个函数的输出是否与下一个函数的输入匹配
1.编译器在使用spread运算符时发出抱怨(但仍能成功推断合成签名)
例如,以下代码将在编译时和运行时工作
虽然这将在运行时抱怨,但正确推断签名并运行
3wabscal3#
下面是TypeScript中强类型组合函数的一个例子,它的缺点是不检查每个中间函数类型,但是它能够为最终组合函数导出arg和返回类型。
我们也可以创建一个强类型管道函数,将数据从第一个函数传输到下一个函数,以此类推。
kg7wmglp4#
TypeScript 4的元组类型改进可以用于
pipe
和compose
函数类型,而无需定义覆盖列表。编译器将确保每个函数都能像预期的那样被下面的函数调用(每个中间函数都进行了类型检查)。
示例:
一个值得注意的限制是TypeScript仍然不能推断泛型函数的Parameter和Return类型。从TypeScript4.7开始,您可以通过使用示例化表达式来帮助编译器。
fsi0uk1n5#
我发现写一个类型化的compose函数并不太难now(TypeScript v4.1.5及以上版本,在TypeScript Playground测试过),这里有一个例子,它可以检查每个中间函数类型。
yi0zb3m46#
我做了一些挖掘,发现了一个很棒的递归解决方案,在注解区的“@cartersnook6139”中,对Matt Pocock's video的一个类型化的compose函数进行了递归。这里有一个到Typescript Playground的链接。它太神奇了!