You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

使用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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.16 07:22:43