使用infer与类型字面量构建NPM组件包时出现编译错误
问题分析与解决方案
我在开发组件NPM包时,写了两个TypeScript类型助手来提取MDI图标的名称(去掉前缀并把驼峰转连字符),代码如下:
export type StripPrefix< T extends string, Prefix extends string > = T extends `${Prefix}${infer R}` ? R : never; export type CamelToHyphen<T extends string> = T extends `${infer L}${infer R}` ? `${L extends Capitalize<L> ? `-${Uncapitalize<L>}` : Uncapitalize<L>}${CamelToHyphen<R>}` : "";
使用方式:
import * as Path from "@mdi/js"; import { CamelToHyphen, StripPrefix } from "../../helpers/type-helpers"; type MdiIcons = keyof typeof Path; type HyphenatedIcon<T extends string, Prefix extends string> = CamelToHyphen< StripPrefix<T, Prefix> > extends `-${infer R}` ? R : ""; export type Icons = HyphenatedIcon<MdiIcons, "mdi">;
执行npm run build时编译器报类型语法错误,但把类型助手代码注释后重新构建,再取消注释重新构建就能正常运行。试过更新Babel配置和插件,问题依然存在,怀疑是Babel对模板字面量类型的支持有问题。
可能的解决方案
1. 确保TypeScript与Babel插件版本兼容
模板字面量类型、Capitalize/Uncapitalize这些特性是TypeScript 4.1及以上版本才支持的。检查你的依赖版本匹配度:
- 升级
typescript到4.1+的稳定版本 - 确保
@babel/preset-typescript是支持对应TS版本的最新版
2. 拆分类型检查与代码转译流程
Babel本身不做类型检查,它的TS插件仅负责移除类型语法。可以拆分构建步骤:
- 用
tsc --noEmit单独完成类型校验 - 用Babel专注转译代码
- 修改
package.json的build脚本示例:"scripts": { "build": "tsc --noEmit && babel src --out-dir dist", "clean": "rimraf dist" }
3. 构建前强制清理缓存
第一次构建可能缓存了错误的类型解析结果,注释再取消注释相当于绕过了缓存。可以在构建前清理缓存:
- 安装
rimraf:npm install rimraf --save-dev - 更新build脚本:
"scripts": { "build": "rimraf dist && tsc && babel src --out-dir dist" }
4. 简化类型助手的递归逻辑
递归的模板字面量类型可能导致Babel的TS插件处理异常,尝试简化写法:
比如将CamelToHyphen改为:
export type CamelToHyphen<T extends string> = T extends `${infer A}${infer B}` ? `${A extends Lowercase<A> ? A : `-${Lowercase<A>}`}${CamelToHyphen<B>}` : "";
如果MDI图标名称格式固定,也可以考虑用预生成的静态类型代替动态推导。
内容的提问来源于stack exchange,提问作者David Mood
相关产品推荐
相关产品推荐

