このサンプルコンポーネントがあります
_import React, { FC, ReactNode, useMemo } from "react";
import PropTypes from "prop-types";
type Props = {
children: ((x: number) => ReactNode) | ReactNode;
};
const Comp: FC<Props> = function Comp(props) {
const val = useMemo(() => {
return 1;
}, []);
return (
<div>
{typeof props.children === "function"
? props.children(val)
: props.children}
</div>
);
};
Comp.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
};
export default Comp;
_
ここでの私の意図は、コンポーネントのchildren
プロパティが
node
、これは
レンダリングできるもの:数値、文字列、要素、またはこれらのタイプを含む配列(またはフラグメント)。
function
、(または「レンダープロップ」)コンポーネント内部から値を取得し、別のnode
を返すだけ
ここでのポイントは明示的です。children
は、1つ(node
、ほとんどすべてです)またはもう1つ(単にfunction
です)のいずれかです。
型チェックで次の問題に直面しています。
? props.children(val)
行に次のエラーメッセージが表示されます。この式は呼び出すことができません。タイプ 'Function | ((x:数値)=> ReactNode)| (文字列&{})| (番号&{})| (false&{})| (真&{})| ({}&文字列)| ({}&番号)| ({}&false)| ({}&true)| (((x:数値)=> ReactNode)&文字列)
このエラーは理解できません。
Props
タイプを次のように変更した場合_type Props = {
children: (x: number) => ReactNode;
};
_
そして、React自身の_type PropsWithChildren<P> = P & { children?: ReactNode };
_に依存して、children
が関数ではない場合を処理すると、エラーが発生します
(プロパティ)子ですか?:PropTypes.Validator <(x:number)=> React.ReactNode>タイプ 'Validator'はタイプ 'Validator <(x:number)=> ReactNode>'に割り当てられません。タイプ 'ReactNodeLike'はタイプ '(x:number)=> ReactNode'に割り当てることができません。タイプ 'string'はタイプ '(x:number)=> ReactNode'.ts(2322)に割り当て可能ではありませんComp.tsx(5、3):予期されるタイプは、タイプでここで宣言されているプロパティ' children 'から取得されます
行children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
唯一の解決策は、Props
タイプをそのままにすることです
_type Props = {
children: (x: number) => ReactNode;
};
_
また、_Comp.propTypes
_を_children: PropTypes.func.isRequired
_に変更します。これは、明示的にしたいのでnotです。
この質問の最初に示したように、コードを明示的にして、型チェックでエラーがスローされないようにするにはどうすればよいですか?
グローバルユニオンが役立つと思います。
type Props = {
children: ((x: number) => ReactNode);
} | {
children: ReactNode;
};
機能し、Props
宣言を別の方法で記述したり、他の何かを別の方法で書き換えたりする必要のない別の解決策は、コンポーネントの定義中にprops
パラメーターの型を厳密に定義することです 、 このような
type Props = {
children: ((x: number) => ReactNode) | ReactNode;
};
const Comp: FC<Props> = function Comp(props: Props) { // we strictly define the props type here
...
}
Comp.propTypes = {
children: PropTypes.oneOfType([PropTypes.node, PropTypes.func]).isRequired
};
これが違いを生む理由は100%わかりません。自分の直感では、独自のProps
定義を型チェッカーに「強制」するため、可能なスコープを制限しています。
元の質問をして以来、私は最終的に自分の問題の次の解決策に落ち着きました:私は自分の関数コンポーネントタイプを定義しました:
//global.d.ts
declare module 'react' {
// Do not arbitrarily pass children down to props.
// Do not type check actual propTypes because they cannot always map 1:1 with TS types,
// forcing you to go with PropTypes.any very often, in order for the TS compiler
// to shut up
type CFC<P = {}> = CustomFunctionComponent<P>;
interface CustomFunctionComponent<P = {}> {
(props: P, context?: any): ReactElement | null;
propTypes?: { [key: string]: any };
contextTypes?: ValidationMap<any>;
defaultProps?: Partial<P>;
displayName?: string;
}
}
このソリューション
children
プロップを私の定義に強制しませんComponent.propTypes
とTS type Props = {...}
を相互参照しません。多くの場合、それらは正確に1:1にマップされず、PropTypes.any
を使用せざるを得ませんでした。TSタイプとともにComponent.propTypes
を保持している理由は、開発中にTSが非常に優れている一方で、ランタイム中にタイプが正しくない場合にPropTypes
が実際に警告するためです。 、APIレスポンスのフィールドは数値であるはずでしたが、現在は文字列になっています。このようなことが起こる可能性があり、TSが支援できるものではありません。
https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34237https://github.com/DefinitelyTyped/DefinitelyTyped/issues/34237#issuecomment-486374424