英文:
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();
}
);
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论