Digamos que quiero usar el patrón de componente de orden superior React para transformar un subconjunto de mis accesorios antes de que lleguen a mi componente:
type UpstreamProps<X> = { foo?: number bar?: string baz: X } type DownstreamProps<X> = { foo: number bar: string baz: X bix: string } function transform<X>(props: UpstreamProps<X>): DownstreamProps<X> { return { ...props, foo: props.foo || 0, bar: props.bar || '(unknown)', bix: `${props.foo}-${props.bar}-bix` } }En la definición del widget, quiero usar accesorios posteriores (estrictos):
function Parent<X>(props: DownstreamProps<X> & {formatter: (x: X) => string}) { return ( <> foo = {props.foo} bar = {props.bar} baz = {props.formatter(props.baz)} bix = {props.bix} </> ) }En el sitio de la llamada, debería poder pasar accesorios ascendentes (opcionales):
<WrappedParent<number> baz={22} formatter={(x: number) => `my number squared is ${Math.pow(x, 2)}`} /> Esto es lo más cerca que he llegado a escribir el componente de orden superior, pero no puedo hacer que funcione bien con los genéricos en Parent / WrappedParent :
function withUpstreamProps<X, OtherProps>( WrappedComponent: React.ComponentType<DownstreamProps<X> & OtherProps> ) { return function({foo, bar, baz, ...otherProps}: UpstreamProps<X> & OtherProps) { return ( <WrappedComponent {...otherProps} {...transform({foo, bar, baz})} /> ) } } export default withUpstreamProps(Parent) // doesn't keep genericsAquí hay dos requisitos que son difíciles de conciliar:
withUpstreamProps(someRandomComponent) debería ser un error. withUpstreamProps solo debe aceptar un componente válido como argumento; es decir, uno que acepta un superconjunto de DownstreamProps<X> .WrappedParent emitido debe ser parametrizado por un parámetro genérico; por ejemplo WrappedParent<number> .¿Cómo puedo escribir y/o usar mi contenedor de componentes de orden superior para cumplir con estos requisitos?
¿Funcionaría algo así para tu caso?:
type Wrapped<X, Other> = React.ComponentType<Output<X> & Other> function withUpstreamProps<C extends Wrapped<any, any>>( WrappedComponent: C ) { return function<X, OtherProps>({foo, bar, baz, ...otherProps}: Input<X> & OtherProps) { return ( <WrappedComponent {...otherProps} {...transform({foo, bar, baz})} /> ) } }Si desea pasar el tipo genérico al componente resultante, la función devuelta por el HOC debe ser genérica y tomar el tipo X como argumento y luego pasarlo a WrappedComponent .
function withUpstreamProps( WrappedComponent: React.FunctionalComponent ) { return function <X, OtherProps>({ foo, bar, baz, ...otherProps }: UpstreamProps<X> & OtherProps) { return ( <WrappedComponent<X> {...otherProps} {...transform({ foo, bar, baz })} /> ); }; } También se debe pasar el tipo OtherProps , de modo que WrappedParent reconozca la función del formatter .
También debe asignar un tipo para la función de formatter cuando use el componente resultante ( WrappedParent )
Si mi respuesta fue útil, se agradecería un voto a favor.