@types/react
パッケージを使用しようとしましたが、問題が発生しました。index.d.ts
のDefinitions by:
を参照)応答。次のコンポーネント
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'.
children
をElement
でラップすると機能します。
context
に何かを追加するだけのプロバイダーコンポーネントを作成する場合、 children
を返すことは非常に一般的です。
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.children
をReact.Children.only(this.props.children)
でラップすることです。これにより、rootとして複数の要素がある場合にスローされます。
そうです、 React.Children.only
を使用できますが、 ReactNode
とReactElement
の両方が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の子を入力できません
これを回避するために、現在children
をReact.Fragment
でラップしています。
それに関する更新はありますか?
これがchildren
をReact.Fragment
でラップするよりも多かれ少なかれ正しいかどうかはわかりませんが、私は運が良かったです
return (children as React.ReactElement);
return <>{foo(}</>;
一晩中。 <>
は回避策です。
これは私にも問題を引き起こしています。
特定のコンポーネントに小道具を追加する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がノードの配列を禁止する必要がある場合、それはReactText
、 ReactPortal
、 boolean
、 null
、およびundefined
を禁止する必要があるという意味ではありません。 ReactElement
の使用法は何をしますか。
これらの追加のタイプを禁止する理由は何ですか?
最も参考になるコメント
これを回避するために、現在
children
をReact.Fragment
でラップしています。