TypeScript 如何做动态导入
前端开发里,动态导入是处理页面资源按需加载的实用技巧——比如做电商网站时,只有用户点进商品详情页才加载对应的详情脚本,能减少初始页面加载体积,提升打开速度。但如果用的是TypeScript,不少开发者会疑惑:TypeScript怎么实现动态导入?其实核心是在JavaScript原生动态导入的基础上,补全TypeScript的类型提示,既保留按需加载的优势,又能享受TS的类型校验。
先搞懂基础:JS的动态导入是什么
先从大家熟悉的JavaScript说起。普通的import是静态导入,页面加载时就会自动把目标脚本拉进来,不管用不用;而动态导入用import()函数(注意是带括号的函数形式),返回一个Promise,只有调用时才加载资源。举个生活化的例子:你订外卖时,不会提前把所有商家的餐都送到家,而是下单(调用import())后,商家才把对应餐品送过来——这就是按需加载。

举个实际的JS例子:
`javascript
// 点击按钮才加载弹窗组件
document.getElementById('openDialog').addEventListener('click', async () => {
// 点击时才加载dialog.js
const dialogModule = await import('./dialog.js');
dialogModule.showDialog();
});
`
这样初始加载时不会带dialog.js,只有用户需要时才加载,省了初始体积。
TypeScript的动态导入:补全类型提示
TypeScript的动态导入,完全兼容JS的import(),只是会自动解析被导入模块的类型——前提是被导入的模块本身有类型定义(比如.ts/.tsx文件,或带.d.ts声明的.js模块)。
还是用弹窗组件的例子,改成TS版本:
`typescript
// 定义dialog模块的类型(如果是.ts文件,TS自动生成)
type DialogModule = {
showDialog: () => void;
hideDialog: () => void;
};
document.getElementById('openDialog')?.addEventListener('click', async () => {
// 1. 自动推断出import返回的是Promise<DialogModule>,不用手动写类型
const dialog = await import('./dialog');
// 2. TS会校验:showDialog是存在的,hideDialog也是,不会写错方法名
dialog.showDialog();
// 报错:TS会提示dialog上没有不存在的方法,提前规避错误
// dialog.wrongMethod();
});
`
这里的关键是:如果被导入的文件是.ts/.tsx,TS会自动根据文件的导出内容生成类型,不需要额外手写;如果是.js文件,就需要补一个类型声明文件(比如dialog.d.ts),告诉TS模块里有什么方法,避免类型报错。
特殊场景:动态导入带变量路径怎么办?
有些时候,导入的路径是动态变化的——比如做多语言网站,要根据用户选的语言导入对应翻译文件,路径是./locales/${lang}.ts。这时候TS需要稍微调整,不能直接用变量拼接路径,否则会报错。
正确的做法是用import.meta.resolve(或TS支持的动态路径写法),让TS能识别路径范围,举个例子:
`typescript
async function loadLocale(lang: 'zh-CN' | 'en-US') {
// TS会识别路径是./locales/下的合法文件,不会乱报错
const localeModule = await import(./locales/${lang}.ts);
return localeModule;
}
// 调用:选中文就加载zh-CN.ts,选英文就加载en-US.ts
loadLocale('zh-CN').then(locale => console.log(locale.greeting));
`
这里要注意,动态路径的变量必须是固定的取值范围(比如上面的lang只能是zh-CN或en-US),不能用任意字符串,否则TS会不知道哪些文件存在,没法做类型校验。
避坑提醒:别踩这两个常见错误
- 不要把
import()写成静态导入:比如写成import dialog from './dialog',这是静态导入,会在页面加载时就执行,失去动态加载的意义,TS还会提示冗余。 - 不要在动态导入里用未知路径:如果路径是不确定的任意字符串,TS会无法做类型校验,还会报错找不到模块,比如
import(./modules/${anyString}.ts)就不合适,必须限定路径的可选值。
总的来说,TypeScript做动态导入,就是在JS原生按需加载的基础上,加上类型校验的“安全锁”,既保留了优化加载速度的优势,又能提前发现代码错误,适合所有需要做性能优化的前端项目。