【问题标题】:Defining the correct types for an HOC injecting a prop为注入 prop 的 HOC 定义正确的类型
【发布时间】:2017-11-04 01:43:26
【问题描述】:

所以我有一组基础组件,其 prop 类型设置为:

type SomeProps = {
  // ... arbitrary prop types
  theme: {
    wrapper: string,
    button: string,
    // these are also kind of arbitrary
  }
}

现在我有一个 HOC 将注入 theme 属性,因此这个新创建组件的用户不必/不应该传递 theme 属性。测试表明以下代码不起作用(合并同一字段的类型)...

type A = { foo: number };
type B = A & { foo?: number };
const x: B = { foo: 2 };

无论如何,我编写了 HOC,但我不确定流类型在我描述的场景中是否有效。作为附加要求,新创建的组件仍然可以传递一个theme 属性,该属性应该与注入的theme 合并。这是 HOC 的代码:

// @flow

import withProps from 'recompose/withProps';
import setDisplayName from 'recompose/setDisplayName';
import wrapDisplayName from 'recompose/wrapDisplayName';
import classnames from 'classnames';

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 };
type OptionalThemePropType = {
    [prop: string]: mixed,
    theme?: ThemeType
}

function mergeTheme<T, U: T & { theme: ThemeType }>(
    injectedTheme: ThemeType
): (BaseComponent: Component<T>) => Component<U> {
    return BaseComponent => {
        const Themed: Component<U> = withProps((ownProps: OptionalThemePropType) => {
            let theme: ThemeType = injectedTheme;
            if (ownProps && ownProps.theme) {
                const ownTheme: ThemeType = ownProps.theme;
                theme = Object
                    .keys(ownTheme)
                    .filter((key: string) => !!injectedTheme[key])
                    .reduce(
                        (accum: ThemeType, key: string) => {
                            accum[key] = classnames(ownTheme[key], injectedTheme[key]);
                            return accum;
                        },
                        { ...ownTheme, ...injectedTheme }
                    );
            }
            return { theme };
        })(BaseComponent);
        setDisplayName(wrapDisplayName(BaseComponent, 'themed'))(Themed);
        return Themed;
    };
}

这对吗?

【问题讨论】:

    标签: reactjs flowtype higher-order-components


    【解决方案1】:

    这个想法是使用$Diff flowtype helper 从组件道具中删除注入的道具。

    @expo/ex-navigation 包的 withNavigation 示例

    declare type FunctionComponent<P> = (props: P) => ?React$Element<any>;
      declare type ClassComponent<D, P, S> = Class<React$Component<D, P, S>>;
      declare type Component<P> = FunctionComponent<P> | ClassComponent<any, P, any>;
    
      declare type ExNavProps = {
        navigation: NavigationContext,
        navigator: ExNavigatorContext,
      };
    
      declare type WithNavigationOptions = {
        withRef: boolean,
      };
    
      // withNavigation should add navigator and navigation as defaultprops for WrappedComponent
      declare function withNavigation<DefaultProps, Props, State>(
        WrappedComponent: ClassComponent<DefaultProps, Props, State>,
        options?: WithNavigationOptions,
      ): ClassComponent<DefaultProps & ExNavProps, $Diff<Props, ExNavProps>, State>;
    

    但是你仍然需要在你的组件中定义 ExNavProps,像这样

    类型道具 = { firstProp:字符串, } & ExNavProps

    export default class MyComponent extends React&lt;void, Props, void&gt;

    【讨论】:

      猜你喜欢
      • 2019-03-02
      • 1970-01-01
      • 1970-01-01
      • 2021-02-05
      • 2020-11-03
      • 1970-01-01
      • 1970-01-01
      • 2015-09-30
      • 2021-07-26
      相关资源
      最近更新 更多