【问题标题】:Flow Bounded Polymorphism of unknown type未知类型的流有界多态性
【发布时间】:2017-07-14 20:07:00
【问题描述】:

我正在尝试创建一个函数,该函数将一个 React 组件和一个对象作为具有正确流类型的参数。所以 React Component 参数应该期待 P 类型的 props,其中 P 应该有属性 theme,它是推断类型 V。我知道V 是字符串对象,但它仍然可以是不同的类型(即{ button: string }{ checkbox: string } 不同)。第二个参数的类型应该是V

该函数的要点是获取一个需要 theme 属性的 React 组件(它只是专门针对该 React 组件的字符串对象)并使用第二个参数作为该属性,返回一个新的 React 组件不需要那个 theme 道具(因为它已经给出了)。

我在这方面做了几次尝试,但仍然没有奏效。

/* @flow */

type FunctionComponent<P> = (props: P) => ?React$Element<any>;
type ClassComponent<D, P, S> = Class<React$Component<D, P, S>>;
type Component<P> = FunctionComponent<P> | ClassComponent<any, P, any>;
type ThemeType = { [className: string]: string };

function mergeTheme<P: { theme: ThemeType }, V: $PropertyType<P, 'theme'>>(
    BaseComponent: Component<P>,
    injectedTheme: V
): FunctionComponent<$Diff<P, { theme: V }>> {
    const ThemedComponent = ownProps => <BaseComponent {...ownProps} theme={injectedTheme} />;
    ThemedComponent.displayName = 'Themed(' + BaseComponent.displayName + ')';
    return ThemedComponent;
}

流量错误

12:     const ThemedComponent = ownProps => <BaseComponent {...ownProps} theme={injectedTheme} />;
                                            ^ props of React element `BaseComponent`. Expected object instead of
12:     const ThemedComponent = ownProps => <BaseComponent {...ownProps} theme={injectedTheme} />;
                                                               ^ object type
12:     const ThemedComponent = ownProps => <BaseComponent {...ownProps} theme={injectedTheme} />;
                                            ^ props of React element `BaseComponent`. Expected object instead of
12:     const ThemedComponent = ownProps => <BaseComponent {...ownProps} theme={injectedTheme} />;
                                                               ^ some incompatible instantiation of `P`

The Try Flow Example

Here's a gist of my various attempts as well

我真正的目标实际上是让新的 React 组件接受一个可选的 theme 参数,然后我会与上面示例中的 injectedTheme 合并,但要先一步一步。

【问题讨论】:

    标签: flowtype


    【解决方案1】:

    目前这似乎运作良好。不知道它是多么正确

    type FunctionComponent<P, C> = (props: P, context: C) => ?React$Element<any>;
    type ClassComponent<D, P, S> = Class<React$Component<D, P, S>>;
    
    declare function mergeTheme<P: { theme: *, [propName: any]: any }, V: $PropertyType<P, 'theme'>>(
        BaseComponent: ClassComponent<*, P, *>,
        injectedTheme: V
    ): FunctionComponent<$Diff<P, { theme: V }> & { theme?: $Shape<V> }, *>;
    
    declare function mergeTheme<P: { theme: *, [propName: any]: any }, V: $PropertyType<P, 'theme'>>(
        BaseComponent: FunctionComponent<P, *>,
        injectedTheme: V
    ): FunctionComponent<$Diff<P, { theme: V }> & { theme?: $Shape<V> }, *>;
    
    function mergeTheme(BaseComponent, injectedTheme) {
        const ThemedComponent = ownProps => {
            let theme = injectedTheme;
            if (ownProps && ownProps.theme) {
                const ownTheme = ownProps.theme;
                theme = Object.keys(ownTheme)
                    .filter(key => !!injectedTheme[key])
                    .reduce((accum, key) => {
                        accum[key] = classnames(ownTheme[key], injectedTheme[key]);
                        return accum;
                    }, { ...ownTheme, ...injectedTheme });
            }
            return <BaseComponent {...ownProps} theme={theme} />;
        };
        const currName = BaseComponent.displayName || BaseComponent.name;
        ThemedComponent.displayName = `Themed(${currName})`;
        return ThemedComponent;
    }
    

    编辑

    所以这并不完全有效。拿这个示例代码:

    type Theme = {|
        someClass: string,
        anotherClass: string
    |};
    
    type Props = { someProp: string, theme: Theme };
    
    const SomeComponent = (props: Props) => <div className={props.theme.someClass}>{props.someProp}</div>;
    
    const ThemedComponent = mergeTheme(SomeComponent, { someClass: 'world', anotherClass: 'idhgo' });
    
    // The line below should work but instead flow complains
    const el1 = <ThemedComponent someProp="hello" theme={{ someClass: 'hello' }} />
    

    有问题的流程错误:

    47: type Props = { someProp: string, theme: Theme };
                                                ^ property `anotherClass`. Property not found in
    52: const el1 = <ThemedComponent someProp="hello" theme={{ someClass: 'poop' }} />
                                                             ^ object literal
    

    Here's a link to the "Try Flow"

    【讨论】:

      猜你喜欢
      • 2016-09-22
      • 1970-01-01
      • 1970-01-01
      • 2020-05-05
      • 1970-01-01
      • 2018-05-20
      • 1970-01-01
      • 1970-01-01
      • 2015-03-09
      相关资源
      最近更新 更多