2017-06-02 80 views
1

所以我有一組具有它的道具類型設定爲基本組件:定義的正確類型的HOC注入道具

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

現在我有這回事注入theme道具,使用戶的HOC這個新創建的組件不需要/不應該通過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; 
    }; 
} 

這是正確的嗎?

回答

0

這個想法是使用$Diff flowtype helper從Component Props中刪除注入的道具。

例如對於@博覽會/ EX導航包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<void, Props, void>