React懒加载引入时遭遇TS2349错误的解决求助
React 18 + TypeScript 动态导入默认导出函数报错解决方法
我正尝试按照React官方文档描述,在React 18项目中用动态import()语法做代码分割,实现懒加载。官方文档提到:
为应用引入代码分割的最佳方式是使用动态import()语法。
原始可运行代码
import addMobileAppStartupListeners from './components/listeners/addMobileAppStartupListeners'; const startApp = () => { if (isPlatformMobile()) { addMobileAppStartupListeners(); } startAccessibilityTestingIfDebug(); };
addMobileAppStartupListeners.tsx代码:
const addMobileAppStartupListeners = () => { document.addEventListener( 'deviceready', () => { // 点击通知时触发的方法 PluginPushNotifactions.addListener( 'pushNotificationActionPerformed', (notification: PluginActionPerformed) => { debugLog('push registration tapped', notification); }, ); }, false, ); }; export default addMobileAppStartupListeners;
尝试动态导入后的报错
因为是默认导出,我尝试用动态导入改写代码:
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基础薄弱,推测需要给导入的函数指定类型,但不知道具体操作方法。
环境详情
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" ] }
问题原因
动态import()返回的是模块对象,默认导出的内容会挂载在这个对象的default属性上。你直接调用模块对象自然会报错——模块本身不是可调用的函数。
修复方法
有三种简单的修复方式:
方式1:解构获取default导出
在then回调里解构出default属性,直接使用:
const startApp = () => { if (isPlatformMobile()) { import('./components/listeners/addMobileAppStartupListeners').then( ({ default: addMobileAppStartupListeners }) => { addMobileAppStartupListeners(); }, ); } startAccessibilityTestingIfDebug(); };
方式2:直接调用模块的default属性
直接访问模块对象的default属性并调用:
const startApp = () => { if (isPlatformMobile()) { import('./components/listeners/addMobileAppStartupListeners').then( (module) => { module.default(); }, ); } startAccessibilityTestingIfDebug(); };
方式3:用async/await简化代码
如果允许startApp变成异步函数,还可以用async/await让代码更简洁:
const startApp = async () => { if (isPlatformMobile()) { const { default: addMobileAppStartupListeners } = await import('./components/listeners/addMobileAppStartupListeners'); addMobileAppStartupListeners(); } startAccessibilityTestingIfDebug(); };
补充说明
静态导入时你用了import addMobileAppStartupListeners from '...',TypeScript(配合allowSyntheticDefaultImports配置)会自动帮你处理默认导出的映射,直接拿到函数本身;但动态import不会做这个自动映射,必须显式访问default属性。
内容的提问来源于stack exchange,提问作者Patrick Kenny
相关产品推荐
相关产品推荐

