Búsqueda de sitios web

reactjs - Declaraciones de tipos de Typescript para Promise que devuelve un Componente de React


Tengo la siguiente función:

const withCacheRefresh = (lazyLoadComponent: any) => {
  return new Promise<React.ComponentType<any>>((resolve) => {
    lazyLoadComponent()
      .then(resolve)
      .catch(() => {
        window.location.reload(true);
      });
  });
}

Toma una promesa como argumento, específicamente lazy. Procedo a llamar a la promesa, ya sea resolviendo la promesa devolviendo el resultado de lazy, o en mi catch, refrescando la página. Me estoy encontrando con problemas con el siguiente error de compilación de Typescript:

Type 'Promise<ComponentType<any>>' is not assignable to type 'Promise<{ default: ComponentType<any>; }>'.
  Type 'ComponentType<any>' is not assignable to type '{ default: ComponentType<any>; }'.
    Property 'default' is missing in type 'ComponentClass<any, any>' but required in type '{ default: ComponentType<any>; }'.  TS2322

Tengo dos preguntas:

  • ¿Cómo puedo especificar que mi primer argumento lazyLoadComponent sea del tipo de una función que devuelve un componente del tipo React.Component<any> en lugar de solo any?

  • ¿Cómo puedo arreglar mi definición de Promise<React.ComponentType<any>> para que cumpla con el tipo requerido de Promise<{ default: ComponentType<any>; }>?

Actualizar

He recibido respuestas diciéndome que mi solución es incorrecta para el problema que planteé, pero elegí intencionalmente omitir detalles sobre las complejidades de mi espacio de problema más amplio.

Ya que se preguntó, siento que no está de más aclarar: cuando se lanzan nuevas implementaciones para mi aplicación, se crean nuevos fragmentos y los antiguos se eliminan del espacio de trabajo de producción. En consecuencia, los clientes que todavía permanecen en la versión anterior (ya que la aplicación no se ha actualizado a la última versión) siguen usando fragmentos antiguos. HMR no funcionaría ya que este es un entorno de producción. Una actualización explícita haría que los service workers recuperaran los fragmentos más recientes.

Se describe una circunstancia similar en este problema de Github.

Respuesta #1

Esta es una forma enrevesada (y ligeramente incorrecta) de hacer las cosas.

Voy a suponer que tienes una razón para recargar la página cuando hay un error que no sea "Espero que esto solucione el error" (si esa es la razón o si es para evitar el caché, definitivamente deberías probar HMR).

EDITAR Dado que el autor original ha aclarado lo que quiso decir, sugeriría, en lugar de esperar que el navegador no almacene en caché el componente cargado de forma diferida y así cause errores cuando se lance una nueva versión, utilizar un manifiesto de precaché en el propio Service Worker, lo que permitiría al SW cargar el manifiesto cada vez que se registre uno nuevo. Consulta esta pregunta para más información. Puedes integrarlo en el propio empaquetador con el plugin de Workbox, incluso si no usas Workbox.

También voy a suponer que quieres usar esto con lazy, no llamarlo en lazy, porque de lo contrario no es exactamente posible capturar ningún error.

import React from 'react';

type LazyFactory = Parameters<typeof React.lazy>[0];

const withCacheRefresh = (
  importResult: LazyFactory
): LazyFactory => () =>
  importResult().catch(() => {
    window.location.reload(true);
    // Following makes return type `never`, which satisfies TypeScript
    throw new Error('component load failed');
  });

No hay necesidad de envolverlo en una promesa porque ya es una. Simplemente puedes usar .catch directamente sobre ella.

Uso :

const MyLazyComponent = React.lazy(withCacheRefresh(() => import('./Component')));