I have the following function:
const withCacheRefresh = (lazyLoadComponent: any) => {
return new Promise<React.ComponentType<any>>((resolve) => {
lazyLoadComponent()
.then(resolve)
.catch(() => {
window.location.reload(true);
});
});
}
It takes in a promise as an argument, specifically lazy. I proceed to call the promise, either resolving the promise by returning the result of lazy, or in my catch, refresh the page. I'm running into issues with the following Typescript compilation error:
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
I have two questions:
How can I specify my first argument lazyLoadComponent to be of the type for a function that returns a component of React.Component<any> type instead of just any?
How can I fix my Promise<React.ComponentType<any>> definition such that it conforms to the required type of Promise<{ default: ComponentType<any>; }> ?
Update
I've received answers telling me that my solution is incorrect for my stated problem, but I purposely chose to omit details about the nuances of my larger problem space.
Since it was asked, I feel like there's no pain clarifying: when new deployments get released for my application, new chunks get created, and the old ones purged from the production workspace. Consequently, clients that still remain in the previous release (since the app hasn't been refreshed to the latest version) are still using old chunks. HMR would not work since this is a production environment. An explicit refresh would cause the service workers to retrieve the latest chunks.
A similar circumstance is described in this Github Issue.
This is a convoluted (and slightly incorrect) way of doing things.
I'm going to assume you have a reason for reloading the page on an error other than "I hope it fixes the error" (if that's the reason or if it's for cache-busting purposes, you should definitely try HMR).
EDIT Since OP has clarified what he meant, I'd suggest, instead of hoping the browser doesn't cache the lazy-loaded component and thereby errors when a new version is rolled out, to use a precache manifest in the Service Worker itself, which would allow the SW to load the manifest whenever a new one is regestired. See this question for more info. You can integrate it into the bundler itself with the Workbox plugin, even if you don't use Workbox.
I'm also going to assume you want to use this with lazy, not call it on lazy, because otherwise it's not exactly possible to catch any errors.
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');
});
There's no need to wrap it in a promise because it already is one. You can just .catch on it directly.
Usage:
const MyLazyComponent = React.lazy(withCacheRefresh(() => import('./Component')));
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With