Open4
多相的forwardRefの型付けメモ
何年もforwardRefとジェネリクスの相性問題は語られてきたが、最近自分の中でほぼ解決している書き方があるので書き残しておく
なおあちこちのものを参照していて1つ1つどれも私が思いついたものではないけど、もうどこを参照したか思い出せないのでScrapで手軽に書いてます。許して…
as
propsを使わない場合
import { FC } from 'react'
type Ref<As extends ElementType> = ComponentPropsWithRef<As>['ref'];
type XProps<T,> = {
...
}
type XComponent = <T,>(props: XProps<T>) => ReturnType<FC>
const X: XComponent = forwardRef(<T,>({...props}: XProps<T>, ref: Ref<...>) => (...)
as
propsを使う場合
import { ComponentPropsWithoutRef, ComponentPropsWithRef, ElementType, FC } from 'react';
type PreservedOmit<T, K extends keyof T> = {
[Property in keyof T as Exclude<Property, K>]: T[Property];
};
type Ref<As extends ElementType> = ComponentPropsWithRef<As>['ref'];
type RefProp<As extends ElementType> = { ref?: Ref<As> };
type AsProp<As extends ElementType> = {
/**
* レンダリングするコンポーネントを指定 (例: button, a, input)
*/
as?: As;
};
type PolyComponentProps<Props extends object, As extends ElementType> = AsProp<As> &
Props &
RefProp<As> &
PreservedOmit<ComponentPropsWithoutRef<As>, keyof (Props & AsProp<As> & RefProp<As>)>;
type XProps<T, As extends ElementType = 'button'> = PolyComponentProps<{...}, As>
type XComponent = <T, As extends ElementType = 'button'>(props: XProps<T, As>) => ReturnType<FC>
const X: XComponent = forwardRef(<T, As extends ElementType = 'button'>({ ...props }: XProps<T, As>, ref: Ref<As>) => {...}
ReturnType<FC>
してるのは、前は JSX.Element | null
とかだったけどTypeScript 5.3?あたりからReactNodeを返すようになってちょっと事情が変わり、JSX.ElementType
でいいみたいな話もあったけどなんかよう動かんときもあるので、ReturnType<FC>
にするのが1番楽で筋が良く問題が起きにくい解決法かなと思ったからです