◆

TypeScript tsconfig forceConsistentCasingInFileNames 强制文件名大小写一致

2023-02-02 01:370

forceConsistentCasingInFileNames 作用

是否强制代码中使用的模块文件名必须和文件系统中的文件名保持大小写一致,

这个选项存在的根本原因是各操作系统的文件系统对大小写的处理不一致。macOS 默认的 APFS 和 Windows 的 NTFS 都是大小写不敏感的(case-insensitive),./fileManager 和 ./FileManager 在它们看来是同一个文件;而 Linux 的 ext4 是大小写敏感的,这两个路径指向两个不同的文件,其中一个根本不存在。

所以典型的事故是这样的:我们在 Mac 上写代码、跑测试、本地构建,一切正常,一提交到跑 Linux 容器的 CI 上就报 Cannot find module './fileManager' 或者 Module not found。代码没错,错的是引入路径的大小写和真实文件名不一致,只是本地的文件系统一直在替我们"纠正"这个错误,把问题藏到了 CI 才爆出来。

forceConsistentCasingInFileNames 的作用就是让 TypeScript 在编译期就把这类不一致当成错误报出来,而不是等到部署环境才发现。

示例

假设我们有一个文件名为 FileManager.ts,我们从这个文件中引入时,默认可以忽略大小写

如下示例,FileManager.ts 是大写的文件名,我们使用小写的引入时,也不会报错

import { getName } from './fileManager';

这里"不会报错"要看清前提:只有在大小写不敏感的文件系统上才不会报错。同一行代码放到 Linux 上直接就找不到模块了。

但当我们开启 forceConsistentCasingInFileNames 为 true 时,引入文件名必须大小写一致,如下

import { getName } from './FileManager';

写错大小写时,TypeScript 会给出这样一条错误,提示信息里会把两个不同写法的路径都列出来,很好认:

error TS1149: File name '/src/fileManager.ts' differs from already included file name '/src/FileManager.ts' only in casing.

怎么配置

在 tsconfig.json 的 compilerOptions 里加上一行即可:

{
  "compilerOptions": {
    "forceConsistentCasingInFileNames": true
  }
}

关于默认值有个变化需要留意:在 TypeScript 5.0 之前这个选项默认是 false,需要手动开;TypeScript 5.0 起默认变成了 true。所以升级到 5.x 之后,一些一直存在但没被发现的大小写不一致会突然开始报错。这不是升级引入的新问题,而是把旧问题暴露了出来,值得直接改掉而不是把选项关回去。

另外 tsc --init 生成的模板配置里一直都带着这一项,新项目基本不用操心。

一个更隐蔽的坑:git 记录里的大小写

修好代码里的引入路径只是一半,另一半在 git 上。如果哪天我们决定把文件本身重命名,比如从 FileManager.ts 改成 fileManager.ts,在大小写不敏感的系统上直接改文件名,git 往往察觉不到这次变更,git status 显示干净,改动推不上去。同事拉下来的还是老名字,CI 上依然找不到模块。

正确的做法是让 git 显式记录这次重命名:

git mv FileManager.ts fileManager.ts

如果 git 拒绝执行(提示目标已存在),可以借一个中间名绕一下:

git mv FileManager.ts temp-name.ts
git mv temp-name.ts fileManager.ts

还可以打开 git 对大小写的敏感度,让它不再把两个只差大小写的路径当作同一个文件:

git config core.ignorecase false

这个配置是仓库级的,改完之后 git status 才能正常报出仅大小写不同的重命名。注意它只影响 git 的行为,不会改变文件系统本身的特性。

实践建议

  • 这个选项没有理由关掉,它只做静态检查,不影响编译产物,也不带来任何运行时开销,开着就是白拿一层保护。
  • 团队约定统一的文件命名风格,比如组件文件一律 PascalCase、工具文件一律 camelCase 或 kebab-case。风格统一之后,凭记忆写引入路径也很少会错。
  • 注意它管不到运行时。forceConsistentCasingInFileNames 只检查 TypeScript 自己解析的模块路径,像 require 拼接出来的动态路径、构建工具的 alias 配置、以及 CSS/静态资源的引入路径,都不在它的检查范围内,这些地方还是得靠 CI 在 Linux 上跑一遍来兜底。
💬留言板0

还没有留言,来发表第一条吧~

PAGE LOAD / LIVETypeScript tsconfig forceConsistentCasingInFileNames 强制文件名大小写一致加载中