理解“无阴影变量”的 tslint 警告

Posted

技术标签:

【中文标题】理解“无阴影变量”的 tslint 警告【英文标题】:Making Sense of 'No Shadowed Variable' tslint Warning 【发布时间】:2017-12-04 19:16:39 【问题描述】:

我有一个函数可以根据传入的特定学科检查顺序流中的当前阶段,并根据该值在我的 Angular 2 应用程序中分配下一个值。它看起来像这样:

private getNextStageStep(currentDisciplineSelected) 
    const nextStageStep = '';
        if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 1') 
            const nextStageStep = 'step 2';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 2') 
            const nextStageStep = 'step 3';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 3') 
            const nextStageStep = 'step 4';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 4') 
            const nextStageStep = 'step 5';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 5') 
            const nextStageStep = 'step 6';
    
    return nextStageStep;

我在这里所做的是返回 nextStageStep 的值,因为这是我将传递的值,以便正确的阶段步骤发生。

现在,我的 tslint 用警告 no shadowed variables 在每个出现的 nextStageStep 变量下划线。如果我删除了我初始化为空字符串的行,警告就会消失,但随后我会收到错误,Cannot find nextStageStep 会出现在我的返回语句中。

原始阴影变量警告有什么问题,是否有替代方法来编写,和/或在这种情况下我应该简单地忽略 tslint 警告吗?

【问题讨论】:

【参考方案1】:

一般来说,当局部范围内的变量和包含范围内的变量同名时,就会发生阴影。阴影使得无法访问包含范围内的变量,并掩盖了标识符实际引用的值。

const a = 'no shadow';
function print() 
    console.log(a);

print(); // logs 'no shadow'.

const a = 'no shadow';
function print() 
    const a = 'shadow'; // TSLint will complain here.
    console.log(a);

print(); // logs 'shadow'.

请参阅此article 以获取解释此问题的代码示例。

【讨论】:

【参考方案2】:

找到并打开您的 tslint.json 文件并将以下设置设置为 false

 "no-shadowed-variable": false,

使用 Visual Studio 时,可能需要重新启动 Visual Studio。

【讨论】:

当提供的代码示例明显包含该规则要防止的不需要的错误时,建议禁用 linting 规则似乎很危险。【参考方案3】:

首先,即使您继续警告,您的函数“getNextStageStep()”也将始终返回空值,

因为“const”a 是块作用域变量,并且

不支持重新定义值[初始化值不能更改]。

return 块中的变量“nextStageStep”包含空字符串值,内部块“nextStageStep”变量不会屏蔽或覆盖外部块的“nextStageStep”变量值。

所以每当你返回“nextStageStep”时,它总是会返回空字符串。

内部块“nextStageStep”变量范围仅在 if 块内,而外部块“nextStageStep”变量与内部块“nextStageStep”变量完全不同。

因此,如果您希望您的代码工作并且如果您必须想要使用const 变量,那么请在 if 块中使用多个 return 语句。

以下是我检查并正常工作的代码。你可以根据你的要求使用它。

function  getNextStageStep(currentDisciplineSelected) 
    const nextStageStep = '';
    if (currentDisciplineSelected === 'step 1') 
        const nextStageStep = 'step 2';
        return nextStageStep;
     else if (currentDisciplineSelected === 'step 2') 
        const nextStageStep = 'step 3';
        return nextStageStep;
     else if (currentDisciplineSelected === 'step 3') 
        const nextStageStep = 'step 4';
        return nextStageStep;
     else if (currentDisciplineSelected === 'step 4') 
        const nextStageStep = 'step 5';
        return nextStageStep;
     else if (currentDisciplineSelected === 'step 5') 
        const nextStageStep = 'step 6';
        return nextStageStep;
    
    return nextStageStep;

console.log(getNextStageStep('step 1'));

但是,最好使用let 变量来编写这些许多返回语句,它允许您重新定义变量值。对于您的问题,我认为 @toskv 解决方案是合适的。

【讨论】:

【参考方案4】:

添加到:https://developer.mozilla.org/en-US/docs/Web/javascript/Reference/Statements/const

ES6 const 是 BLOCK-SCOPED,因此:



    const TAG='<yourIt>';
    console.log(TAG);
 

 
  const TAG = '<touchingBase NoImNOt="true">';
  console.log(TAG);
 

 console.log(TAG);  // ERROR expected

AFAICT,这不是阴影的情况 - 每个常量都正确地放在大括号内。

如果我们不能重复使用变量名,我们最终会得到不可读的、晦涩难懂的程序。而不是告知。

我认为警告是错误的

【讨论】:

您的示例没有隐藏常量T,但最初的问题是nextStageStep。阴影并不意味着该常量被非法重新定义(const x = 1; const x = 2),只是如果您错误地引用了哪个 var/const/let 可能会出现错误。是否允许遮蔽是一个见仁见智的问题,但您可以说这条规则在这里弥补了 OP 的错误,因此您可以看到它是有目的的。【参考方案5】:

linter 抱怨是因为您多次重新定义同一个变量。从而替换包含它的闭包中的那些。

不要重新声明它,只需使用它:

private getNextStageStep(currentDisciplineSelected) 
    let nextStageStep = '';
        if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 1') 
             nextStageStep = 'step 2';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 2') 
             nextStageStep = 'step 3';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 3') 
             nextStageStep = 'step 4';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 4') 
             nextStageStep = 'step 5';
         else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 5') 
             nextStageStep = 'step 6';
    
    return nextStageStep;

【讨论】:

好吧,因为它是一个常数。将其更改为 let 或 var【参考方案6】:

这与在不同范围内定义相同的变量有关。您在函数范围内和每个 if 块内定义 nextStageStep。一种选择是去掉 if 块中的变量声明

if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 1') 
   nextStageStep = 'step 2';
 else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 2') 
   nextStageStep = 'step 3';
 else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 3') 
   nextStageStep = 'step 4';
 else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 4') 
   nextStageStep = 'step 5';
 else if (this.stageForDiscipline(this.currentDisciplineSelected) === 'step 5') 
   nextStageStep = 'step 6';

这是关于阴影变量的好资源http://eslint.org/docs/rules/no-shadow

【讨论】:

除非nextStageStep 被声明为let,而不是const,否则这将不起作用【参考方案7】:

您在每个 if 块中重新声明了相同的变量 const nextStageStep

只需将 const nextStageStep = 'step 2'; 替换为 nextStageStep = 'step 2';(以及所有其他 if 情况)就可以了。

【讨论】:

以上是关于理解“无阴影变量”的 tslint 警告的主要内容,如果未能解决你的问题,请参考以下文章

TSLint 抛出警告

如何禁用 TSLint 警告 - 深度导入

React & Redux tslint 警告

WebPack 在主页上显示 tslint 警告

将 WebStorm TSLint 错误行更改为警告行

VSCode:tslint-language-service 插件将 lint 提示显示为错误而不是警告