Definitelytyped: ReactコンポーネントはReactNodeを返すか、子はReactElementである必要があります

作成日 2017年07月14日  ·  18コメント  ·  ソース: DefinitelyTyped/DefinitelyTyped

  • [x] @types/reactパッケージを使用しようとしましたが、問題が発生しました。
  • [x] tscの最新の安定バージョンを使用してみました。 https://www.npmjs.com/package/typescript
  • [x] StackOverflowに不適切な質問があります。 (そこで適切な質問をしてください)。
  • [x] [メンション](https://github.com/blog/821-mention-somebody-they-re-notified)作成者( index.d.tsDefinitions by:を参照)応答。

    • 著者: @ericanderson @onigoetz @tkrotoff @digiguru @morcerf @johnnyreilly @bbenezech @pzavolinsky @DovydasNavickas

次のコンポーネント

const SFC: React.StatelessComponent = (props) => props.children;

class C extends React.Component {
  render() {
    return this.props.children;
  }
}

エラーを与える

Type '(props: { children?: ReactNode; }) => ReactNode' is not assignable to type 'StatelessComponent<{}>'.
  Type 'ReactNode' is not assignable to type 'ReactElement<any> | null'.
    Type 'undefined' is not assignable to type 'ReactElement<any> | null'.

Class 'C' incorrectly extends base class 'Component<{}, {}>'.
  Types of property 'render' are incompatible.
    Type '() => ReactNode' is not assignable to type '() => false | Element | null'.
      Type 'ReactNode' is not assignable to type 'false | Element | null'.
        Type 'undefined' is not assignable to type 'false | Element | null'.

childrenElementでラップすると機能します。

contextに何かを追加するだけのプロバイダーコンポーネントを作成する場合、 childrenを返すことは非常に一般的です。

最も参考になるコメント

これを回避するために、現在childrenReact.Fragmentでラップしています。

全てのコメント18件

index.d.ts次の修正を試しました

-        render(): JSX.Element | null | false;
+        render(): ReactNode;

-        (props: P & { children?: ReactNode }, context?: any): ReactElement<any> | null;
+        (props: P & { children?: ReactNode }, context?: any): ReactNode;

しかし、リントしようとすると、修正方法がわからないというエラーがいたるところに発生しました。

TypeScript compile error: JSX element type 'ReactNode' is not a constructor function for JSX elements.

いいえ、この変更は正しくありません。 現在、Reactで複数の要素を返すことはできません。 あなたがどこかでそれをしたとしても、おそらくそれはどういうわけか単一のものにカプセル化されています。
React 16 withFiberでのみこれが可能かもしれません:)

反応の動作が変更されたかどうかはわかりませんが、https://egghead.io/lessons/に示すように、redux / reactの作成者は、シンラッパーを作成するためにthis.props.childrenを返す機能を紹介しました(要素にchildContextを追加する場合のみ)。

ただし、react-nativeを使用すると、レンダリングからJSX要素の配列を返すことができます。 回避策は、 this.props.childrenReact.Children.only(this.props.children)でラップすることです。これにより、rootとして複数の要素がある場合にスローされます。

そうです、 React.Children.onlyを使用できますが、 ReactNodeReactElementの両方がthis.props.childrenの有効な値です。

const Title = props => <h1>{props.children}</h1>;
<Title>Woah</Title>

有効で合理的なReactコードです。

react 16で要素の配列を返すことができますが、TSはできないと見なすため、エラーをスローします。

編集:これchildren: JSX.Element[];実行して修正します

これまでの私の経験から、ReactNodeは有効であるはずです。

const Id: React.SFC<{}> = (props) => props.children

const App = ()= > <Id>This should work but instead fails</Id>

これが@types/reactに反映される可能性はありますか?

これがないと、Reactの子を入力できません

これを回避するために、現在childrenReact.Fragmentでラップしています。

それに関する更新はありますか?

これがchildrenReact.Fragmentでラップするよりも多かれ少なかれ正しいかどうかはわかりませんが、私は運が良かったです

return (children as React.ReactElement);

return <>{foo(}</>;一晩中。 <>は回避策です。

これは私にも問題を引き起こしています。

TL; DR:

特定のコンポーネントに小道具を追加するHOCがあり、 return children;を持つ機能コンポーネントで使用しようとしています。 回避策return <>{children}</>;を使用した場合にのみ機能します。

詳細:

HOCの簡略版は次のとおりです。

export interface ExtraProps {
  extraProp1: string;
}

export const withExtraProps = <P extends object>(Component: React.ComponentType<P>) => {
  return class extends React.Component<Omit<P, keyof ExtraProps>> {
    render() {
      const extraProps = {
        extraProp1: 'test'
      };

      return (
        <Component {...this.props as P} {...extraProps} />
      )
    }
  }
}

機能コンポーネントの簡略化されたバージョンは次のとおりです。

interface ComponentProps extends ExtraProps {
  children?: React.ReactNode;
  loadingComponent?: ReactElement;
}

export function ExampleComponent(props: ComponentProps) {
  const { children, loadingComponent } = props;

  const [loading, setLoading] = useState(false);

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      await someAsyncCall();
      setLoading(false);
    }

    fetchData();
  });

  if (loading) {
    return loadingComponent || null;
  }

  return children;
}

// This line errors:
export const FeatureFlag = withExtraProps(ExampleComponent);

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

Argument of type '(props: ComponentProps) => {} | null | undefined' is not assignable to parameter of type 'ComponentType<ComponentProps>'.
  Type '(props: ComponentProps) => {} | null | undefined' is not assignable to type 'FunctionComponent<ComponentProps>'.
    Type '{} | null | undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.
      Type 'undefined' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

戻り型ReactElement | nullをExampleComponentに追加すると、HOCへの受け渡しについての不満はなくなりますが、子を返す場合はエラーが発生します。

export function ExampleComponent(props: ComponentProps): ReactElement | null {
  ...
  ...
  return children; // Type 'ReactNode' is not assignable to type 'ReactElement<any, string | ((props: any) => ReactElement<any, string | ... | (new (props: any) => Component<any, any, any>)> | null) | (new (props: any) => Component<any, any, any>)> | null'.

}

ここにある他の人と同じように、 return <>{children}</>;に変更すると、機能しますが、ひどく不必要に感じます。

@kyrstenkellyと_exact_同じ問題があります-子をレンダリングするReact.FCが渡されるHOC関数。

<> children(...) </>の修正は機能しますが、より良い解決策はまだありますか?

また、この問題があります! 現在、React.Fragmentを使用したラッピングソリューションの提案ソリューションを実行しています

こっちも一緒

interface IIntlMessageProps {
    id: string;
    valuesGiven?: {[key:string]:string};
}

// this doesn't work - -- TS2769 Type 'null' is not assignable to type '(nodes:ReactNodeARray) => ReactNode' | ... | undefined
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children}
        </FormattedMessage>
    )
};
//Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <React.Fragment>{props.children}</React.Fragment>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type 'Element' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> | null = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            <>{props.children}</>
        </FormattedMessage>
    )
};

// Nope -- TS2769 Type '{}' is not assignable to type '(nodes:ReactNodeARray) => ReactNode'
export const IntlMessage: React.FC<IIntlMessageProps> = (props) => {
    return (
        <FormattedMessage id={props.id} values={props.valuesGiven}>
            {props.children ? props.children : undefined}
        </FormattedMessage>
    )
};


私はここでアドバイスされたすべてを試したと思います... :(手がかりはありますか?

解決策は、フラグメントでラップする必要があることです。

import React from 'react'

const Something: React.FC = ({ children }) => (
 <> { children } </>
)

これにより、 Type '({ children }: { children?: ReactNode; }) => ReactNode' is not assignable to type 'FunctionComponentエラーが修正されます。

可能であれば、フラグメントを避け、JSX型システムがJavaScriptやFlow Reactがサポートするのと同じ種類の構造をサポートするようにします。これにより、TypeScriptがサードパーティのライブラリパターンでより適切に機能するようになります。

私が見つけたもう1つの非理想的な点は、特にユーティリティ/ラッパーコンポーネント(ケースインポイント:react-placeholder)で、フラグメントがコンポーネントツリーを深くすることです。 React.ReactElementにキャストすることは、この種のライブラリではより良いアプローチのように思えますが、キャストする必要はありません。

そのタイプを変更するアプローチを試しましたが、新しいタイプの機能コンポーネントを使用してJSXタイプチェックでスタックしました。 私はまだ支店を持っています、私が助けを求めるPRをしたと誓ったかもしれません、それを見つけることができません...

さて、typeがノードの配列を禁止する必要がある場合、それはReactTextReactPortalbooleannull 、およびundefinedを禁止する必要があるという意味ではありません。 ReactElementの使用法は何をしますか。

これらの追加のタイプを禁止する理由は何ですか?

このページは役に立ちましたか?
0 / 5 - 0 評価