reactjs - TS2349 vid import av lazy-loading i React


Jag försöker refaktorera en React 18-app för att använda lazy loading som beskrivs i dokumentationen:

Det bästa sättet att introducera kodsplittring i din app är genom den dynamiska import() syntaxen.

Min ursprungliga kod (fungerande):

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;

Eftersom detta är en standardexport trodde jag att jag kunde använda import:

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

Men TypeScript klagar:

[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.

Jag vet inte hur jag ska fixa det här. Min kunskap om TypeScript är ganska grundläggande. Jag tror att jag behöver ange typen på funktionen som returneras av importen, men jag vet inte hur man gör det.

** Miljödetaljer**

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",
  ],
}

Svar #1

Vad som kanske inte är uppenbart från dokumentationsexemplet är att resultatet av den dynamiska importen är modulen själv:

Returnerar ett löfte som uppfylls med ett modulnamnsobjekt: ett objekt som innehåller alla export från moduleName.

Så om din modul har en standardexport, se till att använda .default-egenskapen för att få din faktiska exporterade funktion:

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