Tipo de mecanografía correcto para el valor de retorno de HOC de inyección de prop anidadas en React

Me pregunto si tengo la escritura correcta para el tipo de retorno de un API HOC en el siguiente escenario:

Tengo un HOC de autenticación,withAuthentication, que inyecta servicios de autenticación en los accesorios de un componente.

Tengo un API HOC,withRestApi, que inyecta llamadas de API, y que a su vez usawithAuthentication.

MyComponent necesita hacer uso dewithRestApiunciones inyectadas de @, y tiene sus propios accesorios.

(En la aplicación real,withAuthentication también necesita un HOC de enrutador de reacción, pero estoy tratando de mantener las cosas lo más simples posible en este ejemplo.)

He basado mi código hasta ahora ena excelente publicación de @James Ravencroft sobre HOC y mecanografiado, y adicionalmenteesta publicación SO en accesorios HOC inyectados, lo que ayudó a resolver un problema en el que los accesorios de HOC estaban expuestos al padre del componente envuelto.

Lo que estoy tratando de lograr es:

El acceso a losthis.props.getResultOfApiCall desde elMyComponent clase, pero oculto para cualquier componente padre.El acceso a losthis.props.isAuthenticated desde elWithRestApi clase, pero oculto para cualquier componente padre. Capacidad para establecercomponentProp enMyComponent desde un componente padre.

Code de la siguiente manera:

MyBase.tsx, que encierra el componente únicamente para demostrar el uso deMyComponentpoyo de @:

import * as React from 'react';

import MyComponent from './MyComponent';

class MyBase extends React.Component {
    public render() {
        return (
            <>
                <h1>RESULT</h1>
                <MyComponent componentProp={'Prop belonging to MyComponent'} />
            </>
        );
    }
}

export default MyBase;

MyComponent.tsx, que utiliza la API:

import * as React from 'react';

import { IWithRestApiProps, withRestApi } from './WithRestApi';

interface IMyComponentProps extends IWithRestApiProps {
    componentProp: string;
}

class MyComponent extends React.Component<IMyComponentProps> {
    public render() {
        return (
            <>
                <h2>Component prop: {this.props.componentProp}</h2>
                <h2>API result: {this.props.getResultOfApiCall()}</h2>
            </>
        );
    }
}

export default withRestApi(MyComponent);

WithAuthentication.tsx (poniendo esto primero porque no es el problema ... por lo que puedo decir):

import * as React from 'react';

export interface IWithAuthenticationProps {
    isAuthenticated: () => boolean;
}

export const withAuthentication = <P extends IWithAuthenticationProps>(Component: React.ComponentType<P>):
    React.ComponentType<Pick<P, Exclude<keyof P, keyof IWithAuthenticationProps>>> =>
    class WithAuthentication extends React.Component<P> {
        public render() {

            const { isAuthenticated, ...originalProps } = this.props as IWithAuthenticationProps; 

            return (
                <Component
                    {...originalProps}
                    isAuthenticated={this.isAuthenticated}
                />
            );
        }

        private readonly isAuthenticated = (): boolean => {
            return true;
        }
    }

WithRestApi.tsx, que contiene el problema de escritura.

import * as React from 'react';

import { IWithAuthenticationProps, withAuthentication } from './WithAuthentication';

export interface IWithRestApiProps extends IWithAuthenticationProps {
    getResultOfApiCall: () => string;
}

export const withRestApi = <P extends IWithRestApiProps>(Component: React.ComponentType<P>):
    React.ComponentType<Pick<P, Exclude<keyof P, keyof IWithRestApiProps>>> =>
    withAuthentication(class WithRestApi extends React.Component<P> {
        public render() {

            const { getResultOfApiCall, ...originalProps } = this.props as IWithRestApiProps; 

            return (
                <Component
                    {...originalProps}
                    getResultOfApiCall={this.getApiData}
                />
            );
        }

        private readonly getApiData = () => {
            if (this.props.isAuthenticated()) {
                return 'Some API result';
            } else {
                return 'Not authenticated';
            }
        }
    }) as React.ComponentType<P>; // TODO - remove this type assertion...?

ste código se construye, pero como puede ver, tuve que escribir-afirmar el valor de retorno de lawithApi HOC aReact.ComponentType<P>. Sin esa afirmación, veo este error de Typecript:

[ts]
Type 'ComponentType<Pick<P, Exclude<keyof P, "isAuthenticated">>>' is not assignable to type 'ComponentType<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>>'.
  Type 'ComponentClass<Pick<P, Exclude<keyof P, "isAuthenticated">>, ComponentState>' is not assignable to type 'ComponentType<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>>'.
    Type 'ComponentClass<Pick<P, Exclude<keyof P, "isAuthenticated">>, ComponentState>' is not assignable to type 'ComponentClass<Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>, ComponentState>'.
      Type 'Pick<P, Exclude<keyof P, "isAuthenticated">>' is not assignable to type 'Pick<P, Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">>'.
        Type 'Exclude<keyof P, "getResultOfApiCall" | "isAuthenticated">' is not assignable to type 'Exclude<keyof P, "isAuthenticated">'.

Esta es la primera vez que necesitoPick..Exclude, así que estoy un poco confuso sobre exactamente cómo se compara el tipo en este caso. Me pregunto si hay algo en la forma en que lo estoy usando aquí que podría mejorarse para eliminar la necesidad de la aserción de tipo.

Respuestas a la pregunta(1)

Su respuesta a la pregunta