TS2349在React中导入延迟加载时发生错误。

huangapple go评论77阅读模式
英文:

TS2349 when import lazy-loading in React

问题

我正在尝试重构一个React 18应用程序,以使用文档中描述的懒加载

> 引入代码拆分到应用程序的最佳方法是使用动态import()语法。

我的原始代码(有效):

import addMobileAppStartupListeners from './components/listeners/addMobileAppStartupListeners';

const startApp = () => {
  if (isPlatformMobile()) {
    addMobileAppStartupListeners();
  }
  startAccessibilityTestingIfDebug();
};

addMobileAppStartupListeners.tsx

const addMobileAppStartupListeners = () => {
  document.addEventListener(
    'deviceready',
    () => {
      // 当点击通知时调用的方法
      PluginPushNotifications.addListener(
        'pushNotificationActionPerformed',
        (notification: PluginActionPerformed) => {
          debugLog('push registration tapped', notification);
        },
      );
    },
    false,
  );
};

export default addMobileAppStartupListeners;

由于这是一个默认导出,我认为我可以使用import:

const startApp = () => {
  if (isPlatformMobile()) {
    import('./components/listeners/addMobileAppStartupListeners').then(
      (addMobileAppStartupListeners) => {
        addMobileAppStartupListeners();
      },
    );
  }
  startAccessibilityTestingIfDebug();
};

但TypeScript会报错:

[react-scripts] ERROR in src/index.tsx:41:9
[react-scripts] TS2349: This expression is not callable.
[react-scripts]   Type 'typeof import("/Users/private/d/ionic/src/components/listeners/addMobileAppStartupListeners")' has no call signatures.

我不知道如何修复这个问题。我对TypeScript的了解相当基础。我认为我需要为import返回的函数提供类型,但我不知道如何做到这一点。

环境详细信息

Typescript 4.9.5

{
  "compilerOptions": {
    "target": "es2017",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "noFallthroughCasesInSwitch": true
  },
  // 配置文件.
  "files": [
    "capacitor.config.ts",
    "ionic.config.json",
    "lingui.config.ts",
  ],
  "include": [
    "src",
    "tests/playwright",
  ],
}
英文:

I am trying to refactor a React 18 app to use lazy loading as described in the docs:

> The best way to introduce code-splitting into your app is through the
> dynamic import() syntax.

My original code (working):

import addMobileAppStartupListeners from './components/listeners/addMobileAppStartupListeners';

const startApp = () => {
  if (isPlatformMobile()) {
   addMobileAppStartupListeners();
  }
  startAccessibilityTestingIfDebug();
};

addMobileAppStartupListeners.tsx

const addMobileAppStartupListeners = () => {
  document.addEventListener(
    'deviceready',
    () => {
      // Method called when tapping on a notification
      PluginPushNotifactions.addListener(
        'pushNotificationActionPerformed',
        (notification: PluginActionPerformed) => {
          debugLog('push registration tapped', notification);
        },
      );
    },
    false,
  );
};

export default addMobileAppStartupListeners;

Since this is a default export I thought I could use import:

const startApp = () => {
  if (isPlatformMobile()) {
    import('./components/listeners/addMobileAppStartupListeners').then(
      (addMobileAppStartupListeners) => {
        addMobileAppStartupListeners();
      },
    );
  }
  startAccessibilityTestingIfDebug();
};

But TypeScript complains:

[react-scripts] ERROR in src/index.tsx:41:9
[react-scripts] TS2349: This expression is not callable.
[react-scripts]   Type 'typeof import("/Users/private/d/ionic/src/components/listeners/addMobileAppStartupListeners")' has no call signatures.

I don't know how to fix this. My knowledge of TypeScript is pretty rudimentary. I think I need to give it the type of the function returned by the import, but I don't know how to do that.

** Environment details***

Typescript 4.9.5

{
  "compilerOptions": {
    "target": "es2017",
    "lib": [
      "dom",
      "dom.iterable",
      "esnext"
    ],
    "allowJs": false,
    "skipLibCheck": true,
    "esModuleInterop": true,
    "allowSyntheticDefaultImports": true,
    "strict": true,
    "forceConsistentCasingInFileNames": true,
    "module": "esnext",
    "moduleResolution": "node",
    "resolveJsonModule": true,
    "isolatedModules": true,
    "noEmit": true,
    "jsx": "react-jsx",
    "noFallthroughCasesInSwitch": true
  },
  // Config files.
  "files": [
    "capacitor.config.ts",
    "ionic.config.json",
    "lingui.config.ts",
  ],
  "include": [
    "src",
    "tests/playwright",
  ],
}

答案1

得分: 2

动态导入的示例文档中可能不太明显的是,动态导入的结果是module本身:

返回一个实现为模块命名空间对象的 promise:一个包含来自 moduleName 的所有导出的对象。

因此,如果你的模块具有默认导出,请确保使用 .default 属性来获取你的实际导出函数:

import('./components/listeners/addMobileAppStartupListeners').then(
  // 结果是包含所有导出的模块,包括默认导出
  (addMobileAppStartupListeners) => {
    // 在这里你想要默认导出的函数
    addMobileAppStartupListeners.default();
  }
);
英文:

What may not be obvious from the docs example, is that the result of the dynamic import is the module itself:

> Returns a promise which fulfills to a module namespace object: an object containing all exports from moduleName.

So if your module has a default export, make sure to use the .default property to get your actual exported function:

import('./components/listeners/addMobileAppStartupListeners').then(
  // Result is the module containing all its exports, including default
  (addMobileAppStartupListeners) => {
    // Here you want the default exported function
    addMobileAppStartupListeners.default();
  }
);

huangapple
  • 本文由 发表于 2023年2月27日 18:46:47
  • 转载请务必保留本文链接:https://go.coder-hub.com/75579459.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定