借助 Typescript 路径映射轻松重构
重构 Typescript 项目最难的部分是更新所有导入路径。虽然我们常用的许多编辑器都能帮上忙,但 Typescript 编译器选项中隐藏着一个强大的选项,可以彻底解决这个问题。
导入路径
导入是任何 Typescript 项目的关键部分,它使我们能够包含来自不同文件的代码。一个典型的 Angular 组件会有这样的导入。
// Imports from node_modules
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
// Import from relative paths
import { UserComponent } from './user.component';
import { SharedAppCode } from '../../../common/sharedCode';
无论你在应用中的哪个位置,从 node_modules 导入代码始终相同。这是因为默认情况下,任何不以“.”或“/”开头的导入都会被默认为在 node_modules 下找到。
对于应用程序中的任何共享代码,根据当前文件所在的位置,您可能有'../common','../../common','../../../common'甚至'../../../../common'!
这些不一致的相对路径非常难看,而且重构代码也非常麻烦。移动包含这些路径的文件时,导入的代码也必须相应地更改。虽然这看起来是个小问题,但在大型应用中很快就会失控。虽然代码编辑器会尽力更新路径,但有时它们还是会失效……
别担心!Typescript 可以让我们完全避免这个问题。
tsconfig 编译器选项:{ 路径:{ ... } }
有一个编译器选项调用路径,它使我们能够设置可以在导入中使用的路径映射。
鉴于以下文件结构,我们将设置两个路径映射。一个用于允许我们在每个模块中导入 sharedCode,而无需相对路径;另一个用于导入环境文件。
src/
├── app/
│ ├── common/
| | └── sharedCode.ts
│ ├── feature/
| | └── user/
| | └── user.module.ts
│ ├── feature2/
| | └── account.module.ts
├── environments/
| └── environments.ts
tsconfig.json
在 tsconfig.json 文件中,我们首先需要设置一个baseUrl来告诉编译器路径的起始位置。在本例中,这个起始位置是src文件夹。
"compilerOptions": {
"baseUrl": "./src",
"paths": {
"~app/*": ["app/*"],
"~environments": ["environments/environment"],
}
}
我们先看一下应用程序的第一个路径映射。
"~app/*": ["app/*"]
这告诉 Typescript 编译器,每当它看到以~app/开头的导入时,它就应该在src/app/文件夹下查找代码。这使我们能够将导入路径更新为'~app/common/sharedCode'。结尾的 /* 表示我们可以包含该点之后的任何文件夹路径。在我们的例子中,这是common/sharedCode。
// BEFORE: user.module.ts
import {...} from '../../common/sharedCode';
// BEFORE: account.module.ts
import {...} from '../common/sharedCode';
// AFTER: user.module.ts, account.module.ts
import {...} from '~app/common/sharedCode';
因此,尽管相对路径不同,两个模块现在共享完全相同的导入路径。希望您能明白为什么这使得重构变得更容易。现在,如果我们更改文件夹结构,导入内容不再需要更改。
您还可以使用显式路径映射。这里我们直接指向环境文件。注意,这次没有使用 * 通配符。这样我们可以缩短导入到该文件的路径。
"~environments": ["environments/environment"]
// BEFORE: user.module.ts
import {...} from '../../../environments/environment';
// BEFORE: account.module.ts
import {...} from '../../environments/environment';
// AFTER: user.module.ts, account.module.ts
import {...} from '~environments';
合理的导入分组
你可能注意到,我的两个路径映射都以 ~ 开头。这样做是为了在使用 Visual Studio Code 组织导入时能够进行合理的分组。如果没有 ~,那么你的app/common导入将与你的外部导入分组。
// EXTERNAL: From node_modules
import { Component } from '@angular/core';
import { Observable } from 'rxjs';
// LOCAL: Path mapped
import { SharedAppCode } from '~app/common/sharedCode';
// LOCAL: Relative path
import { UserComponent } from './user.component';
我非常喜欢使用路径映射来清理我的导入路径。这也意味着,如果我需要重构代码,这将变得轻而易举。你甚至可以根据需要,通过简单的查找和替换来更新导入路径。
Stephen Cooper - AG Grid
高级开发人员 在 Twitter 上关注我@ScooperDev或发布有关此帖子的推文。