2017-01-26 16 views
1

子JSX.Elementsを1つ以上受け入れ、余分なコールバックをReact.cloneElement(child, { onCancel:() => {} }でレンダリングするときに渡すコンポーネントがあると仮定します。子要素をクローンしてTypeScriptで余分な小道具を追加するReactコンポーネントを入力する

質問(抜粋)におけるコンポーネント:アクションに質問(抜粋)で

interface XComponentProps { 
    onCancel: (index: number) => void; 
} 

class XComponent extends React.Component<XComponentProps> { 
    render() { 
     const { onCancel } = this.props; 
     const children = typeof this.props.children === 'function' ? 
      React.cloneElement(this.props.children, { onCancel:() => onCancel() }) : 
      this.props.children.map((child, idx) => (
       React.cloneElement(child, { onCancel:() => onCancel(idx) }) 
      )); 
     return <div>{children}</div>; 
    } 
} 

コンポーネント:

interface UserComponentProps { caption: string } 
const UserComponent = (props: UserComponentProps) => (
    <button onClick={props.onClose}>{props.caption || "close"}</button> 
); 

ReactDOM.render(
    <XComponent onCancel={handleCancel}> 
     <UserComponent /> 
     <UserComponent /> 
     <UserComponent /> 
    </XComponent> 
); 

今TSCはUserComponentがでonCancelを持っていないことを不平を言っていますその小道具のインターフェース定義は、実際にはそうではありません。 1つの最も簡単な修正は、onCancelからUserComponentPropsまでのインターフェイスを手動で定義することです。

しかし、子ノードの小道具定義を変更しないで修正して、コンポーネントが任意のReact要素を受け入れることができるようにしたい。このようなシナリオでは、XComponent(親)レベルで渡された暗黙的な小道具を持つ戻り要素の型を定義する方法はありますか?これは、独自の特性に加えてUserComponentPropsにXComponentPropsのすべてのプロパティを与える

interface UserComponentProps extends XComponentProps { caption: string }

:あなたはインターフェイスの継承を使用することができます

答えて

0

これはできません。 UserComponentがReactDOM.renderコンテキストの親XComponentから受け取る小道具を静的に知る方法はありません。あなたがタイプセーフソリューションをしたい場合は

、機能として子供を使用します。

ここで今XComponent定義

interface XComponentProps { 
    onCancel: (index: number) => void; 
    childrenAsFunction: (props: { onCancel: (index: number) => void }) => JSX.Element; 
} 

class XComponent extends React.Component<XComponentProps> { 
    render() { 
     const { onCancel } = this.props; 
     return <div>{childrenAsFunction({ onCancel })}</div>; 
    } 
} 

あなたUserComponent

<XComponent onCancel={handleCancel} childrenAsFunction={props => 
    <span> 
    <UserComponent {...props} /> 
    <UserComponent {...props} /> 
    </span> 
} /> 

これをレンダリングするために使用することができていますうまく動作します、私はこのパターンを頻繁に使用する必要はありません。 XComponentPropsをリファクタリングして、childrenAsFunctionプロップを関連する部分(ここではonCancel関数)と入力できます。

+0

感謝を変更することなく、それを達成したいです! TSCが親と子の間の関係を知ることができるように、関数として渡すのが理にかなっています。 – shuntksh

0

Extending Interfacesを参照)としていUserComponentPropsはXComponentPropsを拡張します。

あなたが定義されてXComponentPropsのすべてのプロパティを持っているUserComponentPropsを要求したくない場合は、一部のタイプ(Mapped Typesを参照)を使用することができます。

interface UserComponentProps extends Partial<XComponentProps> { caption: string }

をこれがUserComponentPropsにのすべてのプロパティを与えますXComponentPropsを作成しますが、オプションにします。

+0

おかげ@erikamjoh、それは私の現在の回避策はあるが、私は、子コンポーネントの小道具...興味深いソリューションのための – shuntksh

0

JSXでも子を関数として渡すことができます。このようにして、適切なタイピングをいつでも得ることができます。 UserComponents propsインターフェイスはChildPropsを拡張する必要があります。

interface ChildProps { 
    onCancel: (index: number) => void; 
} 

interface XComponentProps { 
    onCancel: (index: number) => void; 
    children: (props: ChildProps) => React.ReactElement<any>; 
} 

class XComponent extends React.Component<XComponentProps> { 
    render() { 
     const { onCancel } = this.props; 
     return children({ onCancel })}; 
    } 
} 


<XComponent onCancel={handleCancel}> 
    { props => <UserComponent {...props} /> } 
</XComponent> 
関連する問題