首页 > 解决方案 > 返回 React 组件的 Promise 的 Typescript 类型声明

问题描述

我有以下功能:

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

它接受一个 Promise 作为参数,特别是lazy。我继续调用承诺,要么通过返回结果来解决承诺,要么lazy在我的捕获中刷新页面。我遇到了以下 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

我有两个问题:

更新


我收到的答案告诉我,我的解决方案对于我陈述的问题是不正确的,但我故意选择省略有关我更大问题空间的细微差别的细节。

既然有人问了,我觉得澄清一下就没有什么痛苦了:当为我的应用程序发布新的部署时,会创建新的块,并从生产工作区中清除旧的块。因此,仍保留在先前版本中的客户端(因为应用程序尚未刷新到最新版本)仍在使用旧块。HMR 不起作用,因为这是一个生产环境。显式刷新会导致服务人员检索最新的块。

这个 Github Issue 中描述了类似的情况。

标签: reactjstypescriptpromise

解决方案


这是一种令人费解(而且有点不正确)的做事方式。

我将假设您有理由在出现错误时重新加载页面,而不是“我希望它能修复错误”(如果这是原因或者是出于缓存清除目的,您绝对应该尝试HMR)。

编辑由于 OP 已经澄清了他的意思,我建议不要希望浏览器不缓存延迟加载的组件,从而在推出新版本时出现错误,而是在 Service Worker 本身中使用预缓存清单,这将允许 SW 在重新注册新清单时加载清单。有关更多信息,请参阅此问题即使您不使用 Workbox ,您也可以使用 Workbox 插件将其集成到打包程序本身中。

我还将假设您想将它与 一起使用lazy,而不是在 上调用它lazy,因为否则不可能完全捕获任何错误。

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');
  });

没有必要将它包装在一个承诺中,因为它已经一个。你可以直接.catch上它。

用法:

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

推荐阅读