以淘宝店铺为例,谈谈 TypeScript ESLint 规则集考量

阅读: 作者:admin   发表于 2022-04-15 10:24

   前言

ESLint 在项目中已经是大家见惯不惯的存在,你可能很厌烦动不动跳出来的 ESLint 报错,也可能很享受经过统一校验的工工整整的代码,无论如何,我的意见是,在稍微正式点的项目中都要有 ESLint 的存在,无论是直接使用简单的 recommend 配置如 extends: ['eslint: recommend'],还是精心研究了一整套适用于自己的规则集,Lint 工具的最大帮助就是保持语法统一,至少项目中的所有 JavaScript 文件应使用统一的单双引号、分号、缩进等风格(仅靠编辑器并不能保证)。

其次,Lint 帮助你的代码更加简洁、有效,如不允许未使用的变量、JSX/TSX 中使用简写的 true 属性( 而不是 )等、还有一点值得一提,ESLint 并不会一直尝试去简化你的代码,在很多情况下它会要求你写更多代码来换取可读性和安全性的提升,尤其是在 TypeScript 场景下,explicit-module-boundary-types 规则会要求你为函数与类方法显式的声明其返回值,switch-exhaustiveness-check 规则会要求你处理联合类型变量的所有类型分支。

本文来自于我在所在团队(淘宝店铺)内部制定、落地、推广 ESLint 规则集的收获,将会简要的介绍一批我认为在 TypeScript 分享中非常有必要的规则,通过这篇文章,你会了解到在制定规则时我们考虑的是什么,对于 TypeScript 代码进行约束的思考,以及如何在自己的团队内推广这一套规则。

另外,淘系技术部前端架构团队正在淘系内推广 AppLint,准备将 ESLint 推广到整个淘系前端作为 CI/CD 的卡口之一,欢迎集团的同学了解并试用。

P.S. 我参与的 QCon+ 专题:TypeScript 在中大型项目中的落地实践[1] 中,淘宝店铺 TypeScript 研发规约落地[2] 这一课程包括了我们团队从 JavaScript 迁移到 TypeScript 以及落地完整的研发规约经验,欢迎来听~

基础约束

为了适应读者可能有的不同的约束严格程度,这里将规则拆分为基础约束与严格约束部分,基础约束的规则以语法统一(包括实际代码与类型部分)为主,推荐所有人在所有项目中使用,即使是个人项目——说实在的,都写 TypeScript 了,还在意这小小的 Lint 规则?而严格约束部分更关注类型以及 ECMAScript、TypeScript 的特殊语法,适合对代码质量要求较高的同学。这里不会给出推荐的错误等级,即使全部是 warn,只要你打开了,至少你也会在以后心情好的时候来修对吧?(对吧?)

array-type

TypeScript 中支持使用 Array 与 T[] 的形式声明数组类型,此规则约束项目中对这两种数组类型的声明。

其支持的配置:

仅使用 Array 或 T[] 其中一种 对于原始类型与类型别名使用 T[],对于对象类型、函数类型等使用 Array(推荐)

为什么?:对于这种效果完全一致的语法,我们需要的只是确定一个规范然后在所有地方使用这一规范。实际上,这一类规则(还有后面的类型断言语法)就类似于单引号/双引号,加不加分号这种基础规则,如果你不能接受上一行代码单引号这一行代码双引号,那么也没理由能接受这里一个 Array 那里一个 number[],另外,我个人推荐统一使用 []。

await-thenable

只允许对异步函数、Promise、PromiseLike 使用 await 调用

为什么:避免无意义的 await 调用。

ban-ts-comment

禁止 @ts- 指令的使用,或者允许其在提供了说明的情况下被使用,如:

// @ts-expect-error 这里的类型太复杂,日后补上 // @ts-nocheck 未完成迁移的文件 

此规则推荐与 prefer-ts-expect-error 搭配使用,详见下方。

为什么:如果说乱写 any 叫 AnyScript,那么乱写 @ts-ignore 就可以叫 IgnoreScript 了。

ban-types

禁止部分值被作为类型标注,此规则能够对每一种被禁用的类型提供特定的说明来在触发此规则报错时给到良好的提示,场景如禁用 {}、Function、object 这一类被作为类型标注,

为什么?使用 {} 会让你寸步难行:类型 {} 上不存在属性 'foo',所以用了 {} 你大概率在下面还需要类型断言回去或者变 any,使用 object Function 毫无意义。

对于未知的对象类型,应使用 Record 对于函数类型,应使用入参、返回值被标注出来的具体类型:type SomeFunc = (arg1: string) => void ,或在未知的场景下使用 type SomeFunc = (...args: any[]) => any。 consistent-type-assertions

TypeScript 支持通过 as 与 <> 两种不同的语法进行类型断言,如:

const foo = {} as Foo; const foo = <Foo>{}; // 类似的还有常量断言 const foo = <const>[1, 2]; const foo = [1, 2, 3] as const; 

这一规则约束使用统一的类型断言语法,我个人一般在 Tsx 中使用 as ,在其他时候尽可能的使用 <>,原因则是 <> 更加简洁。

为什么:类似于 array-type,做语法统一,但需要注意的是在 Tsx 项目中使用 <> 断言会导致报错,因为不像泛型可以通过 来显式告知编译器这里是泛型语法而非组件。

explicit-module-boundary-types

函数与类方法的返回值需要被显式的指定,而不是依赖类型推导,如:

const foo = (): Foo => {}; 

为什么:通过显式指定来直观的区分函数的功能,如副作用等,同时显式指定的函数返回值也能在一定程度上提升 TypeScript Compiler 性能。

no-extra-non-null-assertion

不允许额外的重复非空断言:

// x function foo(bar: number | undefined) {   const bar: number = bar!!!; } 

为什么:额,why not?

prefer-for-of

在你使用 for 循环遍历数组时,如果索引仅仅用来访问数组成员,则应该替换为 for...of。

为什么:如果不是为了兼容性场景,在这种场景下的确没有必要使用 for 循环。

prefer-nullish-coalescing && prefer-optional-chain

使用 ?? 而不是


907彩票在线平台,907彩票在线官网,907彩票在线网址,907彩票在线下载,907彩票在线app,907彩票在线开户,907彩票在线投注,907彩票在线购彩,907彩票在线注册,907彩票在线登录,907彩票在线邀请码,907彩票在线技巧,907彩票在线手机版,907彩票在线靠谱吗,907彩票在线走势图,907彩票在线开奖结果

导航

热点推荐

最新发布

友情链接