ようやく React v18 のキャッチアップを始めたのでメモ。
React.FunctionComponent
(FC), React.Component
に暗黙的に含まれていた children
が除かれた
children
を props として受け取るには明示的に children: ReactNode
のように型定義をする必要がある
// Before const MyComponent: FC = (props) => { return ( <div>{props.children}</div> ); }; // After type MyComponenProps = { children: React.ReactNode; }; const MyComponent: FC<MyComponenProps> = (props) => { return ( <div>{props.children}</div> ); };
受け取る props に children
が定義されてない場合は Type Error になる
import { FC } from 'react'; type MyComponenProps = {}; const MyComponent: FC<MyComponenProps> = (props) => { return ( <div>{props.children}</div> ); };
=> Property 'children' does not exist on type 'MyComponent'.ts (2339)
cf.
- Updates to TypeScript definitions | How to Upgrade to React 18
- [react] React 18 types by eps1lon · Pull Request #56210 · DefinitelyTyped/DefinitelyTyped · GitHub
- React TypeScript children の型のメモ - かもメモ
React.VFC が非推奨になった
React.FC
から children
を除いた React.VFC
がありましたが、React v18 からは React.FC
と同じになったので deprecated になっていました。
// React.FunctionComponent type FC<P = {}> = FunctionComponent<P>; interface FunctionComponent<P = {}> { (props: P, context?: any): ReactElement<any, any> | null; propTypes?: WeakValidationMap<P> | undefined; contextTypes?: ValidationMap<any> | undefined; defaultProps?: Partial<P> | undefined; displayName?: string | undefined; } // @deprecated - Equivalent with `React.FC`. type VFC<P = {}> = VoidFunctionComponent<P>; interface VoidFunctionComponent<P = {}> { (props: P, context?: any): ReactElement<any, any> | null; propTypes?: WeakValidationMap<P> | undefined; contextTypes?: ValidationMap<any> | undefined; defaultProps?: Partial<P> | undefined; displayName?: string | undefined; }
React.FC or JSX.Element ?
React.VFC
は過渡期で React.FC
も変更になる可能性があるので JSX.Element
を使っておくのが良いのでは?という話題がありました。React v18 になって React.VFC
が非推奨になり React.FC
から暗黙的な children
が除かれた (以前の React.VFC
と同じになった) ので JSX.Element
と React.FC
どちらが良いのでしょう?
型の違い
JSX.Element
namespace JSX { interface Element extends React.ReactElement<any, any> { }
React.FC
type FC<P = {}> = FunctionComponent<P>; interface FunctionComponent<P = {}> { (props: P, context?: any): ReactElement<any, any> | null; propTypes?: WeakValidationMap<P> | undefined; contextTypes?: ValidationMap<any> | undefined; defaultProps?: Partial<P> | undefined; displayName?: string | undefined; }
React.FC と JSX.Element の違い
React.FC
はJSX.Element
又はnull
を返す事ができるReact.FC
はpropTypes
,contextTypes
,defaultProps
,displayName
のフィールドを持っている
propTypes
React は組み込みの型チェック機能
cf. PropTypes を用いた型チェック – React
=> TypeScript を使用する場合は使うことはなさそう
contextTypes
propTypes
と同様、コンテクストで受け取る値の型定義をTypescriptなどを使わずに定義する手段のようです。
cf. 【検証】React.FC と React.VFC はべつに使わなくていい説 – KRAY Inc., Legacy Context – React
=> TypeScript を使用する場合は使う必要はなさそう
defaultProps
props にデフォルト値を設定するためのフィールド
FunctionComponent では defaultProps
を使わなくてもデフォルト値を設定できる
また defaultProps
自体が非推奨になっているので使う必然は無さそう
displayName
displayName
文字列はデバッグメッセージに使用されます。通常、コンポーネントを定義する関数またはクラスの名前から推測されるため、明示的に設定する必要はありません。
cf. React.Component – React
=> デバック用のフィールドで明示的に設定する必要はないとドキュメントに書かれているので使うことは無さそう
React.FC と JSX.Element どちらを使うのかの個人的な結論
React.FC
は JSX.Element
か null
を返せるという型という認識で良さそう。
null
を含むかどうかの違いしかないので、 React.FC
, JSX.Element
プロジェクト・チームで統一されるならどちらでも良いのでは?と感じました。
個人的な好みでは props の型をジェネリクスで渡せるので React.FC
の方が好みです。特に props の型名が長くなると Reat.FC
の方がコンポーネント名直後に型がまとまるので見通しが良いように感じます。
type MyComponentProps = { onClick: () => void; children: React.ReactNode; } // JSX.Element const MyComponentJSXElement = ({ onClick, children }: MyComponentProps): JSX.Element | null => { // … }; // React.FC import { FC } from 'react'; const MyComponentFC: FC<MyComponentProps> = ({ onClick, children }) => { // ... }
cf.
まとめ
- React v18 では暗黙的に props に含まれていた
children
は、使用するなら明示的に props の型を定義しなければならなくなったchildren
の型が定義されてない状態でprops.children
を使用するとエラーになるchildren
の型はReact.ReactNode
を使えばOK
React.VFC
はReact.FC
と同じになったので非推奨になった
[参考]