在流程中,支持$Compose函数(请参阅recompose as example)。但是,我似乎在 typescript 中找不到这种机制。看来最好的 typescript 可以做的就是https://github.com/reactjs/redux/blob/master/index.d.ts#L416-L460。什么是Typescript中的$Compose等效?

编辑:我想要完成的是从composerecompose键入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)整洁,但它并不可怕,并且扩展性比编写许多重载要好。

10-08 02:12