2017-07-14 19 views
1

我想要一個函數,它需要一個React組件和一個對象作爲正確的流式輸入參數。所以反應組件參數應該期望類型爲P的道具,其中P應該具有屬性theme,其推斷類型爲V。我知道V是字符串的一個對象,但它仍然可以是不同的類型(即{ button: string }不同於{ checkbox: string })。第二個參數應該是V流未知類型的有界多態性

該函數的要點是獲取一個React組件,該組件需要prop theme(它只是該React Component的一個字符串對象),並使用第二個參數作爲該prop,返回一個新的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

我真正的目標其實是有新的陣營組件接受一個可選的theme參數,我會再與合併injectedTheme從上面的例子,但嬰兒的步驟第一。

回答

0

這似乎現在工作良好。不知道如何正確雖然是:

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; 
} 

編輯

所以這完全不起作用。就拿這個例子代碼:

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"

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' }} /> 

有問題的流量誤差