在流程中,支持$Compose
函数(请参阅recompose as example)。但是,我似乎在 typescript 中找不到这种机制。看来最好的 typescript 可以做的就是https://github.com/reactjs/redux/blob/master/index.d.ts#L416-L460。什么是Typescript中的$Compose
等效?
编辑:我想要完成的是从compose
或recompose
键入redux
函数,以便它是类型安全的。特别是,在 react 高阶分量时,我想确保一个HOC的输出 Prop 满足下一个HOC的输入 Prop 。这是我当前的解决方法,并且似乎工作得相当不错-尽管我希望有一种很好的方法可以在 typescript 中以 native 方式进行此操作。
/** 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)
}
最佳答案
您的问题对我来说有点不清楚-似乎依赖于我所缺少的关于React的一些背景-但我正在阅读,内容如下:
坏消息是您不能直接键入此函数。 funs
数组是个问题-为compose
提供最通用的类型,funs
应该是类型对齐的函数列表-每个函数的输出必须与下一个的输入匹配。在TS数组中,数组是同类型的-funs
的每个元素都必须具有完全相同的类型-因此,您无法在TypeScript中直接表达类型在整个列表中变化的方式。 (上面的JS在运行时有效,因为类型被删除并且数据被统一表示。)这就是Flow的$Compose
是一种特殊的内置类型的原因。
解决此问题的一种方法是执行示例中的操作:使用不同数量的参数为compose
声明一堆重载。
function compose<T1, T2, T3>(
f : (x : T2) => T3,
g : (x : T1) => T2
) : (x : T1) => T3
function compose<T1, T2, T3, T4>(
f : (x : T3) => T4,
g : (x : T2) => T3,
h : (x : T1) => T2
) : (x : T1) => T4
function compose<T1, T2, T3, T4, T5>(
f : (x : T4) => T5,
g : (x : T3) => T4,
h : (x : T2) => T3,
k : (x : T1) => T2
) : (x : T1) => T5
显然,这无法扩展。您必须停在某个地方,如果用户需要编写比您预期更多的功能,他们会打赌。
另一种选择是重写代码,以使您一次只能编写一个函数:
function compose<T, U, R>(g : (y : U) => R, f : (x : T) => U) : (x : T) => R {
return x => f(g(x));
}
这就使调用代码更加困惑了-您现在必须编写单词
compose
及其附带的括号O(n)次。compose(f, compose(g, compose(h, k)))
这样的函数组合管道在函数式语言中很常见,那么程序员如何避免这种语法上的不适呢?例如,在Scala中,
compose
是一个中缀函数,可减少嵌套的括号。f.compose(g).compose(h).compose(k)
在Haskell中,
compose
拼写为(.)
,这使得结构非常简洁:f . g . h . k
实际上,您可以在TS中一起破解一个缀
compose
。这个想法是用执行合成的方法将底层函数包装在一个对象中。您可以将该方法称为compose
,但是我将其称为_
,因为它的噪音较小。class Comp<T, U> {
readonly apply : (x : T) => U
constructor(apply : (x : T) => U) {
this.apply = apply;
}
// note the extra type parameter, and that the intermediate type T is not visible in the output type
_<V>(f : (x : V) => T) : Comp<V, U> {
return new Comp(x => this.apply(f(x)))
}
}
// example
const comp : (x : T) => R = new Comp(f)._(g)._(h)._(k).apply
仍不及
compose(f, g, h, k)
整洁,但它并不可怕,并且扩展性比编写许多重载要好。