2017-04-13 78 views
0

我試圖編寫更高階的組件來檢查用戶是否已通過身份驗證。我使用15.5.4做出反應,並@類型/反應15.0.21,和我(簡化)代碼如下:類型安全高階React組件和無狀態功能組件

import * as React from 'react'; 

interface IAuthProps { 
    authenticated: boolean 
} 

function authenticated1<Props extends Object>(wrapped: React.ComponentClass<Props> | React.SFC<Props>): 
    React.SFC<Props & IAuthProps> { 
    return (props: Props & IAuthProps): React.ReactElement<any> => { 
    if (props.authenticated) { 
     return React.createElement(wrapped, props); 
    } else { 
     return <h1>Unauthorized!</h1> 
    } 
    } 
} 

然而,在編譯調用失敗createElement

TS2345:Argument of type 'ComponentClass<Props> | StatelessComponent<Props>' is not assignable to parameter of type 'ComponentClass<Props>'. 
    Type 'StatelessComponent<Props>' is not assignable to type 'ComponentClass<Props>'. 
    Type 'StatelessComponent<Props>' provides no match for the signature 'new (props?: Props | undefined, context?: any): Component<Props, ComponentState>' 

由於@types/reactReact.createElement聲明爲超載函數,並且Typescript can't resolve overloads with union types錯誤並不讓人驚訝。

然而@types/react提供了在工會每種合格的過載(SFCEelement繼承ReactElement所以返回類型兼容):

function createElement<P>(
    type: ComponentClass<P>, 
    props?: Attributes & P, 
    ...children: ReactNode[]): ReactElement<P>; 

function createElement<P>(
    type: SFC<P>, 
    props?: Attributes & P, 
    ...children: ReactNode[]): SFCElement<P>; 

爲了使代碼編譯我只是需要強制打字稿考慮要麼爲聯合類型的相應分支重載,但我不知道如何做到這一點。

如何區分ComponentClassSFC以使Typescript爲類型檢查選擇相應的過載?


PS:目前我只是迫使它通過傳遞wrapped as React.ComponentClass<Props>這是安全的挑頭超載,因爲超載都叫出它接受兩個參數類型相同的運行時功能,但我寧願不喜歡在這裏「作弊」,而是讓系統保證安全。

回答

0

我認爲目前不可能這樣做,因爲它需要改變類型定義。

要使用Type Guard功能可以縮小對象的類型,我們需要擴展一些定義。

interface StatelessComponent<P> { 
    (props: P & { children?: ReactNode }, context?: any): ReactElement<any>; 
    type: 'StatelessComponent'; // NEW ONE 
    propTypes?: ValidationMap<P>; 
    contextTypes?: ValidationMap<any>; 
    defaultProps?: Partial<P>; 
    displayName?: string; 
} 

interface ComponentClass<P> { 
    new (props?: P, context?: any): Component<P, ComponentState>; 
    type: 'ComponentClass'; // NEW ONE 
    propTypes?: ValidationMap<P>; 
    contextTypes?: ValidationMap<any>; 
    childContextTypes?: ValidationMap<any>; 
    defaultProps?: Partial<P>; 
    displayName?: string; 
} 

然後我們將能夠做這樣的事情

function createElementWrapper<Props extends Object>(wrapped: React.ComponentClass<Props> | React.SFC<Props>, props: any) { 
    if (wrapped.type === "StatelessComponent") { 
    return React.createElement(wrapped, props); // wrapped is a StatelessComponent 
    } else { 
    return React.createElement(wrapped, props); // wrapped is a ComponentClass 
    } 
} 

這可能是一個好主意,以創建關於在definitelytyped庫這一問題的問題

相關問題