TypeScriptとReact-子供のタイプ?


137

次のような非常にシンプルな機能コンポーネントがあります。

import * as React from 'react';

export interface AuxProps  { 
    children: React.ReactNode
 }


const aux = (props: AuxProps) => props.children;

export default aux;

そして別のコンポーネント:

import * as React from "react";

export interface LayoutProps  { 
   children: React.ReactNode
}

const layout = (props: LayoutProps) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {props.children}
        </main>
    <Aux/>
);

export default layout;

次のエラーが発生し続けます。

[ts] JSX要素タイプ 'ReactNode'は、JSX要素のコンストラクタ関数ではありません。タイプ 'undefined'はタイプ 'ElementClass'に割り当てることができません。[2605]

これを正しく入力するにはどうすればよいですか?

回答:


132

ただ children: React.ReactNode


これが正解です。JSX.Element有効なReactの子は文字列、ブール値、nullである可能性があるため、これは十分ではありません... ReactChild同じ理由でも不完全です
ピエールフェリー

2
@PierreFerry問題は、ほとんどすべてをに割り当てることができることReactNodeです。タイプセーフと同様に、タイプタイピングchildrenと同様に役立ちませんany- 説明については私の回答を参照してください。
ford04

返信@ ford04をありがとう。私のユースケースでは、子供たちが緩くタイプされることを望みます。私のコンポーネントは、あらゆる種類の有効なReact子を受け入れます。だから私はこれが私が探していた答えであると信じています:)
ピエールフェリー

47

<Aux>JSXで使用するには、を返す関数である必要がありますReactElement<any> | null。これが関数コンポーネントの定義です

ただし、現在React.ReactNodeは、より広い型であるを返す関数として定義されています。Reactタイピングが言うように:

type ReactNode = ReactChild | ReactFragment | ReactPortal | boolean | null | undefined;

戻り値をReact Fragment(<></>)でラップすることにより、不要なタイプが無効化されていることを確認してください:

const aux: React.FC<AuxProps> = props =>
  <>{props.children}</>;

childrenReact Fragmentでラップする必要がある理由がわかりません。説明してもいいですか?Reactでは、それだけで完全に有効ですreturn children;
sanfilippopablo 19/07/25

1
children配列ではない場合。その場合は、それらを単一のノードでラップするか、React Fragmentsを使用する必要があります。
Karol Majewski

ええ、私のコードでは:return React.Children.count(children) > 1 ? <>{children}</> : childrenですが、typescriptはそれについて不平を言っています。ただと入れ替えました<>{children}</>
sanfilippopablo

2
childrenはたまたま1つの項目しか含まない要素のリストであるため、文句を言います。return React.Children.count(children) > 1 ? <>{children}</> : children[0]@sanfilippopablo
tamj0rd2 '17

これは、Reactの新しいバージョンでは機能していないようです。私はコンソールにログを記録し、私が子供の小道具を持っていることを確認できますが、<React.Fragment>周囲{props.children}にいても何も返しません。
マーク

34

これは私のために働いたものです:

interface Props {
  children: JSX.Element[] | JSX.Element
}

編集私はchildren: React.ReactNode代わりに今使用することをお勧めします。


8
それは十分に広い定義ではありません。子は文字列である可能性があります。
Mike S

私のコンポーネントは1つ以上のJSX.Elementsを想定しているはずなので、少なくともこの例はうまくいきました。ありがとう!
Italo Borges

1
これは、子としてのJavaScript式では機能しません<MyComponent>{ condition ? <span>test</span> : null}</MyComponent>。使用してchildren: ReactNode動作します。
Nickofthyme

10

次のようにコンポーネントを宣言できます。

const MyComponent: React.FunctionComponent = (props) => {
    return props.children;
}

9

あなたは使用することができますReactChildrenReactChild

import React, { ReactChildren, ReactChild } from 'react';

interface AuxProps {
  children: ReactChild | ReactChildren;
}

const Aux = ({ children }: AuxProps) => (<div>{children}</div>);

export default Aux;

6

TypeScriptサイトから:https : //github.com/Microsoft/TypeScript/issues/6471

推奨される方法は、小道具タイプを{children ?: any}と書くことです。

それでうまくいきました。子ノードはさまざまなものになる可能性があるため、明示的なタイピングではケースが見落とされる可能性があります。

フォローアップの問題については、https//github.com/Microsoft/TypeScript/issues/13618でより長い議論がありますが、どのアプローチも引き続き機能します。


6

関数コンポーネントの戻り値の型はJSXElement | nullTypeScriptに限定されます。これは現在の型制限であり、純粋なReact はより多くの戻り型を許可します。

最小限のデモスニペット

回避策として、型アサーションまたはフラグメントのいずれかを使用できます。

const Aux = (props: AuxProps) => <>props.children</>; 
const Aux2 = (props: AuxProps) => props.children as ReactElement; 

ReactNode

children: React.ReactNode目標がの強い型を持つことである場合、最適とは言えないかもしれませんAux

現在のReactNodeタイプにはほとんど何でも割り当てることができます{} | undefined | null。これはと同等です。あなたのケースのより安全なタイプは次のとおりです:

interface AuxProps {
  children: ReactElement | ReactElement[]
}

例:

AuxとしてReact要素が必要であることを考慮してchildren、誤っstringてそれにa を追加しました。次に、上記の解決策は対照的にエラーになりますReactNode-リンクされた遊び場を見てください。

Typed childrenは、Render Propコールバックなどの非JSXプロップにも役立ちます。


5

も使用できますReact.PropsWithChildren<P>

type ComponentWithChildProps = React.PropsWithChildren<{example?: string}>;

3

一般的な任意の型を見つける方法は一例です。typescriptの優れている点は、正しいファイルを持っている限り、すべてのタイプにアクセスできること@types/です。

これに自分で答えるために、私はただ、childrenプロップを備えたコンポーネントの反応使用を考えました。最初に思い浮かんだことは?どう<div />ですか?

必要なのは、vscodeを開き.tsx、reactプロジェクトで新しいファイルを作成することだけです@types/react

import React from 'react';

export default () => (
  <div children={'test'} />
);

children小道具にカーソルを合わせると、タイプが表示されます。そして、あなたは何を知っていますか?そのタイプはReactNode(必要ありませんReactNode[])です。

ここに画像の説明を入力してください

次に、型定義をクリックすると、インターフェースchildrenからの定義に直接移動しDOMAttributesます。

// node_modules/@types/react/index.d.ts
interface DOMAttributes<T> {
  children?: ReactNode;
  ...
}

注:このプロセスは、不明なタイプを見つけるために使用する必要があります!それらはすべてあなたがそれらを見つけるのを待っているだけです:)


2

子を含む型として、私は使用しています:

type ChildrenContainer = Pick<JSX.IntrinsicElements["div"], "children">

この子コンテナタイプは、さまざまなケースをすべてサポートするのに十分汎用的であり、ReactJS APIとも整合しています。

したがって、あなたの例では、それは次のようになります:

const layout = ({ children }: ChildrenContainer) => (
    <Aux>
        <div>Toolbar, SideDrawer, Backdrop</div>
        <main>
            {children}
        </main>
    <Aux/>
)

1

これらの回答は古くなっているようです-Reactには組み込み型がありPropsWithChildren<{}>ます。これは、このページのいくつかの正解と同様に定義されています。

type PropsWithChildren<P> = P & { children?: ReactNode };


1
Pそのタイプの場合は何ですか?
sunpietro

Pコンポーネントのプロップのタイプです
Tim Iles

-2

Reactコンポーネントは、単一のラッパーノードを持つか、ノードの配列を返す必要があります。

あなたの<Aux>...</Aux>コンポーネントは、2つのノードがあるdivとしますmain

子をdivin Auxコンポーネントでラップしてみてください。

import * as React from 'react';

export interface AuxProps  { 
  children: React.ReactNode
}

const aux = (props: AuxProps) => (<div>{props.children}</div>);

export default aux;

1
違います。React 16+では、これは当てはまりません。また、当てはまる場合、エラーはこれを示します
Andrew Li
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.