跳至主要内容

命名约定

强制整个代码库中所有内容的命名约定。

💭

此规则需要 类型信息 才能运行。

强制命名约定有助于保持代码库的一致性,并减少思考如何命名变量的开销。此外,精心设计的样式指南可以帮助传达意图,例如强制所有私有属性以 _ 开头,所有全局级常量都以 UPPER_CASE 编写。

注意

此规则已功能冻结:它将不再接收新功能,例如新选项。它仍然会接受其现有功能区域的错误和文档修复,以及支持新的 TypeScript 版本。

强制命名和/或排序约定的样式规则往往会随着越来越模糊的功能的请求而变得难以理解地复杂。此规则已达到 typescript-eslint 项目可以维护的合理范围的极限。有关更多信息,请参见 eslint-plugin: 功能冻结命名和排序样式规则

.eslintrc.cjs
module.exports = {
"rules": {
"@typescript-eslint/naming-convention": "error"
}
};

在游乐场中尝试此规则 ↗

示例

此规则允许您为任何标识符强制执行约定,使用细粒度的选择器来创建细粒度的样式指南。

注意

此规则仅在特定情况下需要类型信息,如下所述。

选项

此规则接受一个对象数组,每个对象描述一个不同的命名约定。每个属性将在下面详细描述。另请参见下面的示例部分以获取说明性示例。

type Options = {
// format options
format:
| (
| 'camelCase'
| 'strictCamelCase'
| 'PascalCase'
| 'StrictPascalCase'
| 'snake_case'
| 'UPPER_CASE'
)[]
| null;
custom?: {
regex: string;
match: boolean;
};
leadingUnderscore?:
| 'forbid'
| 'require'
| 'requireDouble'
| 'allow'
| 'allowDouble'
| 'allowSingleOrDouble';
trailingUnderscore?:
| 'forbid'
| 'require'
| 'requireDouble'
| 'allow'
| 'allowDouble'
| 'allowSingleOrDouble';
prefix?: string[];
suffix?: string[];

// selector options
selector: Selector | Selector[];
filter?:
| string
| {
regex: string;
match: boolean;
};
// the allowed values for these are dependent on the selector - see below
modifiers?: Modifiers<Selector>[];
types?: Types<Selector>[];
}[];

// the default config is similar to ESLint's camelcase rule but more strict
const defaultOptions: Options = [
{
selector: 'default',
format: ['camelCase'],
leadingUnderscore: 'allow',
trailingUnderscore: 'allow',
},

{
selector: 'import',
format: ['camelCase', 'PascalCase'],
},

{
selector: 'variable',
format: ['camelCase', 'UPPER_CASE'],
leadingUnderscore: 'allow',
trailingUnderscore: 'allow',
},

{
selector: 'typeLike',
format: ['PascalCase'],
},
];

格式选项

每个选择器都可以具有相同的格式选项集。有关每个选择器如何应用的信息,请参见 "此规则如何评估名称的格式?"

format

format 选项定义了标识符允许的格式。此选项接受以下值的数组,标识符可以匹配其中任何一个。

  • camelCase - 标准 camelCase 格式 - 字符之间不允许使用下划线,允许连续大写字母(例如,myIDmyId 均有效)。
  • PascalCase - 与 camelCase 相同,但第一个字符必须是大写。
  • snake_case - 标准 snake_case 格式 - 所有字符必须是小写,允许使用下划线。
  • strictCamelCase - 与 camelCase 相同,但不允许连续大写字母(例如,myId 有效,但 myID 无效)。
  • StrictPascalCase - 与 strictCamelCase 相同,但第一个字符必须是大写。
  • UPPER_CASE - 与 snake_case 相同,但所有字符必须是大写。

除了数组之外,您还可以传递 null。这表示“此选择器不应检查其格式”。如果您想在应用组选择器后对特定选择器不强制执行任何特定格式,这将很有用。

custom

custom 选项定义一个自定义正则表达式,标识符必须(或不必须)匹配该正则表达式。此选项允许您对标识符进行更细粒度的控制,让您禁止(或强制)某些模式和子字符串。接受具有以下属性的对象

  • match - 如果标识符必须匹配 regex,则为 true,如果标识符不必须匹配 regex,则为 false。
  • regex - 一个字符串,然后传递给 RegExp 以创建一个新的正则表达式:new RegExp(regex)

filter

filter 选项的操作类似于 custom,接受相同形状的对象,只是它控制是否应该或不应该将其余配置应用于标识符。

您可以使用它将特定标识符包含或排除在特定配置之外。

接受具有以下属性的对象

  • match - 如果标识符必须匹配 regex,则为 true,如果标识符不必须匹配 regex,则为 false。
  • regex - 一个字符串,然后传递给 RegExp 以创建一个新的正则表达式:new RegExp(regex)

或者,filter 接受一个正则表达式(任何可以接受到 new RegExp(filter) 的内容)。在这种情况下,它被视为您传递了一个具有正则表达式和 match: true 的对象。

leadingUnderscore / trailingUnderscore

leadingUnderscore / trailingUnderscore 选项控制是否将前导/尾部下划线视为有效。接受以下值之一

  • allow - 不明确强制执行单个前导/尾部下划线的存在。
  • allowDouble - 不明确强制执行双前导/尾部下划线的存在。
  • allowSingleOrDouble - 不明确强制执行单个或双前导/尾部下划线的存在。
  • forbid - 前导/尾部下划线完全不允许。
  • require - 必须包含单个前导/尾部下划线。
  • requireDouble - 必须包含两个前导/尾部下划线。

prefix / suffix

prefix / suffix 选项控制标识符必须存在的哪个前缀/后缀字符串。接受字符串数组。

如果提供这些,则标识符必须以提供的其中一个值开头。例如,如果您提供 { prefix: ['Class', 'IFace', 'Type'] },则以下名称有效:ClassBarIFaceFooTypeBaz,但名称 Bang 无效,因为它不包含任何前缀。

注意:上面所述,在验证格式之前会修剪前缀,因此必须使用 PascalCase 以允许使用前缀 is 的变量,例如 isEnabled

选择器选项

  • selector 允许您指定要定位的标识符类型。
    • 接受一个或多个选择器数组来定义一个选项块,该选项块应用于一个或多个选择器。
    • 例如,如果您提供 { selector: ['function', 'variable'] },则它将对变量和函数节点应用相同的选项。
    • 有关允许的选择器的完整列表,请参见下面的允许的选择器、修饰符和类型
  • modifiers 允许您指定要细粒度应用的修饰符,例如可访问性 (#private/private/protected/public),或者该事物是否为 static 等。
    • 名称必须与所有修饰符匹配。
    • 例如,如果您提供 { modifiers: ['private','readonly','static'] },则它只会匹配 private static readonly 的内容,而 private 的内容将不匹配。
    • 允许以下 modifiers
      • abstractoverrideprivateprotectedreadonlystatic - 匹配任何使用给定修饰符显式声明的成员。
      • async - 匹配任何通过 async 关键字异步的方法、函数或函数变量(例如,不匹配不使用 async 关键字返回 promise 的函数)
      • const - 匹配声明为 const 的变量 (const x = 1)。
      • destructured - 匹配通过对象解构模式声明的变量 (const {x, z = 2})。
        • 注意,这不会匹配重命名的解构属性 (const {x: y, a: b = 2})。
      • exported - 匹配从模块中导出的任何内容。
      • global - 匹配在顶层作用域中声明的变量/函数。
      • #private - 匹配任何具有私有标识符的成员(以 # 开头的标识符)
      • public - 匹配任何显式声明为 public 或没有可见性修饰符(即隐式 public)的成员。
      • requiresQuotes - 匹配任何需要引号的名称,因为它不是有效的标识符(例如,在其中包含空格、连字符等)。
      • unused - 匹配任何未使用的内容。
  • types 允许您指定要匹配的类型。此选项仅支持简单、原始类型 (array,boolean,function,number,string)。
    • 名称必须与一种类型匹配。
    • 注意 - 使用此选项将需要您使用类型信息进行 lint。
    • 例如,这允许您执行诸如强制 boolean 变量以动词为前缀之类的操作。
    • 允许以下 types
      • array 匹配任何可分配给 Array<unknown> | null | undefined 的类型
      • boolean 匹配任何可分配给 boolean | null | undefined 的类型
      • function 匹配任何可分配给 Function | null | undefined 的类型
      • number 匹配任何可分配给 number | null | undefined 的类型
      • string 匹配任何可分配给 string | null | undefined 的类型

选择器的顺序无关紧要。实现将自动对选择器进行排序,以确保它们从最具体到最不具体进行匹配。它将按此顺序继续检查选择器,直到找到一个与名称匹配的选择器。请参阅 "规则如何自动排序选择器?"

允许的选择器、修饰符和类型

选择器有两种类型:单个选择器和分组选择器。

单个选择器

单个选择器匹配特定的、定义明确的集合。每个单个选择器之间没有重叠。

  • classicAccessor - 匹配任何访问器。它指的是附加到 getset 语法的函数。
    • 允许的 修饰符abstractoverrideprivateprotectedpublicrequiresQuotesstatic
    • 允许的 类型arraybooleanfunctionnumberstring
  • autoAccessor - 匹配任何自动访问器。自动访问器只是一个以 accessor 关键字开头的类字段。
    • 允许的 修饰符abstractoverrideprivateprotectedpublicrequiresQuotesstatic
    • 允许的 类型arraybooleanfunctionnumberstring
  • class - 匹配任何类声明。
    • 允许的 修饰符abstractexportedunused
    • 允许的 类型:无。
  • classMethod - 匹配任何类方法。也匹配具有直接函数表达式或箭头函数表达式值的属性。不匹配访问器。
    • 允许的 修饰符abstractasyncoverride#privateprivateprotectedpublicrequiresQuotesstatic
    • 允许的 类型:无。
  • classProperty - 匹配任何类属性。不匹配具有直接函数表达式或箭头函数表达式值的属性。
    • 允许的 修饰符abstractoverride#privateprivateprotectedpublicreadonlyrequiresQuotesstatic
    • 允许的 类型arraybooleanfunctionnumberstring
  • enum - 匹配任何枚举声明。
    • 允许的 修饰符exportedunused
    • 允许的 类型:无。
  • enumMember - 匹配任何枚举成员。
    • 允许的 修饰符requiresQuotes
    • 允许的 类型:无。
  • function - 匹配任何命名函数声明或命名函数表达式。
    • 允许的 修饰符asyncexportedglobalunused
    • 允许的 类型:无。
  • import - 匹配命名空间导入和默认导入(即不匹配命名导入)。
    • 允许的 修饰符defaultnamespace
    • 允许的 类型:无。
  • interface - 匹配任何接口声明。
    • 允许的 修饰符exportedunused
    • 允许的 类型:无。
  • objectLiteralMethod - 匹配任何对象字面量方法。也匹配具有直接函数表达式或箭头函数表达式值的属性。不匹配访问器。
    • 允许的 修饰符asyncpublicrequiresQuotes
    • 允许的 类型:无。
  • objectLiteralProperty - 匹配任何对象字面量属性。不匹配具有直接函数表达式或箭头函数表达式值的属性。
    • 允许的 修饰符publicrequiresQuotes
    • 允许的 类型arraybooleanfunctionnumberstring
  • parameter - 匹配任何函数参数。不匹配参数属性。
    • 允许的修饰符destructuredunused
    • 允许的 类型arraybooleanfunctionnumberstring
  • parameterProperty - 匹配任何参数属性。
    • 允许的修饰符privateprotectedpublicreadonly
    • 允许的 类型arraybooleanfunctionnumberstring
  • typeAlias - 匹配任何类型别名声明。
    • 允许的 修饰符exportedunused
    • 允许的 类型:无。
  • typeMethod - 匹配任何对象类型方法。也匹配具有直接函数表达式或箭头函数表达式值的属性。不匹配访问器。
    • 允许的 修饰符publicrequiresQuotes
    • 允许的 类型:无。
  • typeParameter - 匹配任何泛型类型参数声明。
    • 允许的修饰符unused
    • 允许的 类型:无。
  • typeProperty - 匹配任何对象类型属性。不匹配具有直接函数表达式或箭头函数表达式值的属性。
    • 允许的修饰符publicreadonlyrequiresQuotes
    • 允许的 类型arraybooleanfunctionnumberstring
  • variable - 匹配任何const / let / var 变量名。
    • 允许的修饰符asyncconstdestructuredexportedglobalunused
    • 允许的 类型arraybooleanfunctionnumberstring
组选择器

组选择器是为了方便提供,本质上是将一组单独的选择器捆绑在一起。

  • default - 匹配所有内容。
    • 允许的修饰符:所有修饰符。
    • 允许的 类型:无。
  • accessor - 匹配与classicAccessorautoAccessor 相同的内容。
    • 允许的 修饰符abstractoverrideprivateprotectedpublicrequiresQuotesstatic
    • 允许的 类型arraybooleanfunctionnumberstring
  • memberLike - 匹配与classicAccessorautoAccessorenumMembermethodparameterPropertyproperty 相同的内容。
    • 允许的修饰符abstractasyncoverride#privateprivateprotectedpublicreadonlyrequiresQuotesstatic
    • 允许的 类型:无。
  • method - 匹配与classMethodobjectLiteralMethodtypeMethod 相同的内容。
    • 允许的修饰符abstractasyncoverride#privateprivateprotectedpublicreadonlyrequiresQuotesstatic
    • 允许的 类型:无。
  • property - 匹配与classPropertyobjectLiteralPropertytypeProperty 相同的内容。
    • 允许的修饰符abstractasyncoverride#privateprivateprotectedpublicreadonlyrequiresQuotesstatic
    • 允许的 类型arraybooleanfunctionnumberstring
  • typeLike - 匹配与classenuminterfacetypeAliastypeParameter 相同的内容。
    • 允许的修饰符abstractunused
    • 允许的 类型:无。
  • variableLike - 匹配与functionparametervariable 相同的内容。
    • 允许的修饰符asyncunused
    • 允许的 类型:无。

常见问题解答

这是一个很大的规则,有很多文档。这里有一些人们经常问到的或通过反复试验得出的澄清。

规则如何评估选择器?

每个选择器按以下方式检查

  1. 检查filter
    1. 如果filter被省略 → 跳过此步骤。
    2. 如果名称与filter匹配 → 继续评估此选择器。
    3. 如果名称与filter不匹配 → 跳过此选择器并继续下一个选择器。
  2. 检查selector
    1. 如果selector是一个单独的选择器 → 名称的类型必须是该类型。
    2. 如果selector是一个组选择器 → 名称的类型必须是分组类型之一。
    3. 如果selector是一个选择器数组 → 对数组中的每个选择器应用上述操作。
  3. 检查types
    1. 如果types被省略 → 跳过此步骤。
    2. 如果名称在types中具有类型 → 继续评估此选择器。
    3. 如果名称在types中没有类型 → 跳过此选择器并继续下一个选择器。

如果名称满足以下条件,则认为它通过了配置

  1. 匹配一个选择器并通过该选择器的所有格式检查。
  2. 不匹配任何选择器。

如果名称匹配一个选择器但未通过该选择器的一个格式检查,则认为它未通过配置。

规则如何自动排序选择器?

每个标识符应精确匹配一个选择器。它可以匹配多个组选择器 - 但始终只匹配一个选择器。考虑到这一点 - 基本排序顺序是

  1. 单个选择器
  2. 分组选择器
  3. 默认选择器

在每个类别中,会根据提供的选择器选项进行进一步排序

  1. filter优先级最高,高于其他所有内容。
  2. types
  3. modifiers
  4. 其他所有内容

例如,如果您提供以下配置

[
/* 1 */ { selector: 'default', format: ['camelCase'] },
/* 2 */ { selector: 'variable', format: ['snake_case'] },
/* 3 */ { selector: 'variable', types: ['boolean'], format: ['UPPER_CASE'] },
/* 4 */ { selector: 'variableLike', format: ['PascalCase'] },
];

那么对于代码const x = 1,规则将按以下顺序验证选择器:3241。为了清楚地说明

  • (3) 首先进行测试,因为它具有types并且是一个单独的选择器。
  • (2) 接下来进行测试,因为它是一个单独的选择器。
  • (4) 接下来进行测试,因为它是一个分组选择器。
  • (1) 最后进行测试,因为它是一个基本默认选择器。

值得注意的是,虽然应用了此顺序,但并非所有选择器都会在名称上运行。这在"规则如何评估名称的格式?"中解释。

规则如何评估名称的格式?

当检查标识符的格式时,按以下顺序进行检查

  1. 验证前导下划线
  2. 验证尾随下划线
  3. 验证前缀
  4. 验证后缀
  5. 验证自定义
  6. 验证格式

对于步骤 1-4,如果标识符与选项匹配,则匹配的部分将被移除。这样做是为了让你能够应用像 PascalCase 这样的格式,而不用担心前缀或下划线导致它不匹配。

最后需要注意的是,如果名称通过此修剪过程变为空,则认为它匹配所有format。这在泛型类型参数中可能很有用,你希望所有名称都以T为前缀,但也希望允许单个字符T名称。

以下是一些示例,以帮助说明

名称:_IMyInterface 选择器

{
"leadingUnderscore": "require",
"prefix": ["I"],
"format": ["UPPER_CASE", "StrictPascalCase"]
}
  1. name = _IMyInterface
  2. 验证前导下划线
    1. 提供配置
    2. 检查名称 → 通过
    3. 修剪下划线 → name = IMyInterface
  3. 验证尾随下划线
    1. 未提供配置 → 跳过
  4. 验证前缀
    1. 提供配置
    2. 检查名称 → 通过
    3. 修剪前缀 → name = MyInterface
  5. 验证后缀
    1. 未提供配置 → 跳过
  6. 验证自定义
    1. 未提供配置 → 跳过
  7. 验证格式
    1. 对于每个格式...
      1. format = 'UPPER_CASE'
        1. 检查格式 → 失败。
          • 重要的是要注意,如果你提供多个格式 - 名称只需要匹配其中一个
      2. format = 'StrictPascalCase'
        1. 检查格式 → 成功。
  8. 成功

名称:IMyInterface 选择器

{
"format": ["StrictPascalCase"],
"trailingUnderscore": "allow",
"custom": {
"regex": "^I[A-Z]",
"match": false
}
}
  1. name = IMyInterface
  2. 验证前导下划线
    1. 未提供配置 → 跳过
  3. 验证尾随下划线
    1. 提供配置
    2. 检查名称 → 通过
    3. 修剪下划线 → name = IMyInterface
  4. 验证前缀
    1. 未提供配置 → 跳过
  5. 验证后缀
    1. 未提供配置 → 跳过
  6. 验证自定义
    1. 提供配置
    2. regex = new RegExp("^I[A-Z]")
    3. regex.test(name) === custom.match
    4. 失败 → 报告并退出

如果我为组选择器提供modifiers 会发生什么?

一些组选择器接受modifiers。在大多数情况下,它们的工作方式与单个选择器完全相同。有一个例外,即修饰符可能不适用于组选择器涵盖的所有单个选择器。

例如 - memberLike 包含enumMember 选择器,它允许protected 修饰符。enumMember 永远不可能是protected,这意味着以下配置将永远不会匹配任何enumMember

{
"selector": "memberLike",
"modifiers": ["protected"]
}

为了帮助匹配,无法指定可访问性的成员将始终具有public 修饰符。这意味着以下配置将始终匹配任何enumMember

{
"selector": "memberLike",
"modifiers": ["public"]
}

示例

强制所有变量、函数和属性遵循驼峰命名法

{
"@typescript-eslint/naming-convention": [
"error",
{ "selector": "variableLike", "format": ["camelCase"] }
]
}

强制私有成员以下划线为前缀

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "memberLike",
"modifiers": ["private"],
"format": ["camelCase"],
"leadingUnderscore": "require"
}
]
}

强制布尔变量以允许的动词为前缀

注意:上面所述,在验证格式之前会修剪前缀,因此必须使用帕斯卡命名法才能允许诸如isEnabled之类的变量。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"types": ["boolean"],
"format": ["PascalCase"],
"prefix": ["is", "should", "has", "can", "did", "will"]
}
]
}

强制所有变量使用驼峰命名法或大写字母命名法

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"format": ["camelCase", "UPPER_CASE"]
}
]
}

强制所有常量变量使用大写字母命名法

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"modifiers": ["const"],
"format": ["UPPER_CASE"]
}
]
}

强制类型参数(泛型)以T为前缀

这允许您模拟旧的generic-type-naming规则。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "typeParameter",
"format": ["PascalCase"],
"prefix": ["T"]
}
]
}

强制接口名称不以I开头

这允许您模拟旧的interface-name-prefix规则。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "interface",
"format": ["PascalCase"],
"custom": {
"regex": "^I[A-Z]",
"match": false
}
}
]
}

强制函数名称使用驼峰命名法或帕斯卡命名法

函数名称通常使用驼峰命名法,但 UI 库组件(尤其是 JSX,如 React 和 Solid)使用帕斯卡命名法来区分它们与内在元素。如果您正在编写函数组件,请考虑允许函数使用驼峰命名法和帕斯卡命名法。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "function",
"format": ["camelCase", "PascalCase"]
}
]
}

强制变量和函数名称使用驼峰命名法

这允许你使用相同的模式来 lint 多种类型。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": ["variable", "function"],
"format": ["camelCase"],
"leadingUnderscore": "allow"
}
]
}

忽略需要引号的属性

有时你必须使用违反命名规范的带引号的名称(例如,HTTP 头)。如果这在你的代码库中很常见,那么你有几个选择。

如果你只想允许所有需要引号的属性名称,你可以使用 requiresQuotes 修饰符来匹配任何需要引号的属性名称,并使用 format: null 来忽略名称。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": [
"classProperty",
"objectLiteralProperty",
"typeProperty",
"classMethod",
"objectLiteralMethod",
"typeMethod",
"accessor",
"enumMember",
],
"format": null,
"modifiers": ["requiresQuotes"],
},
],
}

如果你有一小部分已知的例外情况,你可以使用 filter 选项来仅忽略这些特定的名称。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "property",
"format": ["strictCamelCase"],
"filter": {
// you can expand this regex to add more allowed names
"regex": "^(Property-Name-One|Property-Name-Two)$",
"match": false,
},
},
],
}

你可以使用 filter 选项来忽略包含特定字符的名称。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "property",
"format": ["strictCamelCase"],
"filter": {
// you can expand this regex as you find more cases that require quoting that you want to allow
"regex": "[- ]",
"match": false,
},
},
],
}

请注意,无法忽略任何带引号的名称,只能忽略需要引号的名称。这是故意的 - 在名称周围添加引号不是正确命名的逃生舱。如果你想为特定名称提供逃生舱,可以使用 eslint-disable 注释

忽略解构的名称

有时你可能希望允许解构的属性保留其原始名称,即使它违反了你的命名规范。

你可以使用 destructured 修饰符来匹配这些名称,并明确设置 format: null 来不应用任何格式。

{
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "variable",
"modifiers": ["destructured"],
"format": null,
},
],
}

强制代码库遵循 ESLint 的 camelcase 约定

{
"camelcase": "off",
"@typescript-eslint/naming-convention": [
"error",
{
"selector": "default",
"format": ["camelCase"]
},

{
"selector": "variable",
"format": ["camelCase", "UPPER_CASE"]
},
{
"selector": "parameter",
"format": ["camelCase"],
"leadingUnderscore": "allow"
},

{
"selector": "memberLike",
"modifiers": ["private"],
"format": ["camelCase"],
"leadingUnderscore": "require"
},

{
"selector": "typeLike",
"format": ["PascalCase"]
}
]
}

何时不使用它

此规则可能非常严格。如果你对强制命名规范没有强烈的需求,我们建议仅使用它来标记你命名标准的严重违规行为。如果你有这样的流程,请考虑记录你的命名规范并在代码审查中强制执行它们。

如果您不想对任何内容强制执行命名约定,可以禁用此规则。

但是,请记住,不一致的样式可能会损害项目的可读性。我们建议,如果您关心命名约定,请为该规则选择一个最适合您项目的选项。


类型检查的 lint 规则比传统的 lint 规则更强大,但也需要配置 类型检查的 lint。如果您在启用类型检查规则后遇到性能下降,请参阅 性能故障排除

资源