Skip to main content

no-shadow

Disallow variable declarations from shadowing variables declared in the outer scope.

🧱

This is an "extension" rule that replaces a core ESLint rule to work with TypeScript. See Rules > Extension Rules.

This rule extends the base no-shadow rule from ESLint core. 它增加了对 TypeScript 的 this 参数和全局增强的支持,并增加了 TypeScript 功能的选项。

¥It adds support for TypeScript's this parameters and global augmentation, and adds options for TypeScript features.

如何使用

eslint.config.mjs
export default tseslint.config({
rules: {
// Note: you must disable the base rule as it can report incorrect errors
"no-shadow": "off",
"@typescript-eslint/no-shadow": "error"
}
});

在线运行试试这个规则 ↗

选项

See eslint/no-shadow's options.

¥Options

该规则添加了以下选项:

¥This rule adds the following options:

type AdditionalHoistOptionEntries = 'types' | 'functions-and-types';

type HoistOptionEntries =
| BaseNoShadowHoistOptionEntries
| AdditionalHoistOptionEntries;

interface Options extends BaseNoShadowOptions {
hoist?: HoistOptionEntries;
ignoreTypeValueShadow?: boolean;
ignoreFunctionTypeParameterNameValueShadow?: boolean;
}

const defaultOptions: Options = {
...baseNoShadowDefaultOptions,
hoist: 'functions-and-types',
ignoreTypeValueShadow: true,
ignoreFunctionTypeParameterNameValueShadow: true,
};

hoist:types

{ "hoist": "types" } 选项的错误代码示例:

¥Examples of incorrect code for the { "hoist": "types" } option:

type Bar<Foo> = 1;
type Foo = 1;
Open in Playground

hoist:functions-and-types

{ "hoist": "functions-and-types" } 选项的错误代码示例:

¥Examples of incorrect code for the { "hoist": "functions-and-types" } option:

// types
type Bar<Foo> = 1;
type Foo = 1;

// functions
if (true) {
let b = 6;
}

function b() {}
Open in Playground

ignoreTypeValueShadow

Whether to ignore types named the same as a variable. Default: true.

这通常是安全的,因为你不能在没有 typeof 运算符的情况下在类型位置使用变量,因此混淆的风险很小。

¥This is generally safe because you cannot use variables in type locations without a typeof operator, so there's little risk of confusion.

带有 { ignoreTypeValueShadow: true } 的正确代码示例:

¥Examples of correct code with { ignoreTypeValueShadow: true }:

type Foo = number;
interface Bar {
prop: number;
}

function f() {
const Foo = 1;
const Bar = 'test';
}
Open in Playground
注意

遮蔽特指位于不同嵌套作用域中的两个相同标识符。这与重新声明不同,重新声明是两个相同的标识符位于同一范围内。重新声明由 no-redeclare 规则涵盖。

¥Shadowing specifically refers to two identical identifiers that are in different, nested scopes. This is different from redeclaration, which is when two identical identifiers are in the same scope. Redeclaration is covered by the no-redeclare rule instead.

ignoreFunctionTypeParameterNameValueShadow

Whether to ignore function parameters named the same as a variable. Default: true.

每个函数类型的参数都会在该函数类型的范围内创建一个值变量。这样做是为了你以后可以使用 typeof 运算符引用该类型:

¥Each of a function type's arguments creates a value variable within the scope of the function type. This is done so that you can reference the type later using the typeof operator:

type Func = (test: string) => typeof test;

declare const fn: Func;
const result = fn('str'); // typeof result === string

这意味着函数类型参数影子值变量名称在父作用域中:

¥This means that function type arguments shadow value variable names in parent scopes:

let test = 1;
type TestType = typeof test; // === number
type Func = (test: string) => typeof test; // this "test" references the argument, not the variable

declare const fn: Func;
const result = fn('str'); // typeof result === string

如果你不在函数类型返回类型位置使用 typeof 运算符,则可以安全地启用此选项。

¥If you do not use the typeof operator in a function type return type position, you can safely turn this option on.

带有 { ignoreFunctionTypeParameterNameValueShadow: true } 的正确代码示例:

¥Examples of correct code with { ignoreFunctionTypeParameterNameValueShadow: true }:

const test = 1;
type Func = (test: string) => typeof test;
Open in Playground

常见问题

¥FAQ

为什么规则报告与父作用域中的变量共享相同名称的枚举成员?

¥Why does the rule report on enum members that share the same name as a variable in a parent scope?

报告此案例不是错误 - 它是完全有意且正确的报告!规则报告由于枚举的一个相对未知的功能 - 枚举成员在枚举范围内创建一个变量,以便可以在枚举中引用它们而无需限定符。

¥Reporting on this case isn't a bug - it is completely intentional and correct reporting! The rule reports due to a relatively unknown feature of enums - enum members create a variable within the enum scope so that they can be referenced within the enum without a qualifier.

用一个例子来说明这一点:

¥To illustrate this with an example:

const A = 2;
enum Test {
A = 1,
B = A,
}

console.log(Test.B);
// what should be logged?

天真地看上面的代码,日志可能看起来应该输出 2,因为外部变量 A 的值是 2 - 但是,代码会输出 1,它是 Test.A 的值。这是因为非限定代码 B = A 相当于完全限定代码 B = Test.A。由于这种行为,枚举成员已遮蔽外部变量声明。

¥Naively looking at the above code, it might look like the log should output 2, because the outer variable A's value is 2 - however, the code instead outputs 1, which is the value of Test.A. This is because the unqualified code B = A is equivalent to the fully-qualified code B = Test.A. Due to this behavior, the enum member has shadowed the outer variable declaration.

'## 资源'

Taken with ❤️ from ESLint core.