使用 ESLint 避免 JavaScript 和 React 项目中的不安全调用

使用 ESLint 避免 JavaScript 和 React 项目中的不安全调用

📜✨ 在现代 JavaScript 和 React 应用程序中,经常会遇到由访问“未定义”或“空”值的属性或调用未定义数组或对象的方法引起的运行时错误。这些问题可能会破坏用户体验并使调试成为一场噩梦。在本文中,我们将识别常见问题并提供 ESLint 配置以有效缓解这些问题。🌟💻

🌟✨ 在我们的 React 或 React Native 项目中,由于我们没有使用 TypeScript,我们有时会忘记编写安全代码。这些不安全的代码可能会导致生产中的许多问题,例如 React Native 应用程序崩溃、用户沮丧以及维护复杂化。让我们深入研究这些常见问题及其解决方法。🚨🚀💔

不安全呼叫的常见问题

1. 访问未定义或 null 的属性🌟🔍✨

问题:

访问对象上“未定义”或“空”的属性会导致运行时错误:

const user = undefined;
console.log(user.name); // ❌ Runtime Error: Cannot read property 'name' of undefined

解决方案:

  • 解决方案 1:使用可选链接(?.)。
  • const name = user?.name;
  • 解决方案 2:采用默认后备。
  • const name = user ? user.name : 'Default Name';
  • 解决方案3:确保访问前初始化。
  • const user = { name: 'Default Name' };

    2. 在 undefined 或 null 时调用方法 ✋📉📋

    问题:

    在未定义的数组上调用 `.map()` 或 `.filter()` 等方法会引发错误:

    const items = undefined;
    items.map((item) => console.log(item)); // ❌ Runtime Error: Cannot read property 'map' of undefined

    解决方案:

  • 解决方案 1:验证变量是否为数组。
  • if (Array.isArray(items)) {
      items.map(item => console.log(item));
    }
  • 解决方案 2:提供一个默认数组。
  • const items = someValue || [];
    items.map(item => console.log(item));
  • 解决方案 3:使用空值合并运算符(??)。
  • const items = possibleItems ?? [];

    3. 调用未定义的函数⚙️⚠️🚫

    问题:

    尝试调用可能未定义的函数:

    const handler = undefined;
    handler(); // ❌ Runtime Error: handler is not a function

    解决方案:

  • 解决方案 1:调用前检查存在性。
  • if (typeof handler === 'function') {
      handler();
    }
  • 解决方案 2:分配一个无操作的默认函数。
  • const handler = passedHandler || (() => {});

    4. 解构未定义或空对象

    问题:

    从未定义对象解构属性会导致错误:

    const obj = undefined;
    const { name } = obj; // ❌ Runtime Error: Cannot destructure property 'name' of undefined

    解决方案:

  • 解决方案 1:使用带有默认值的可选链接。
  • const { name = 'Default Name' } = user || {};
  • 解决方案 2:解构之前进行验证。
  • if (user) {
      const { name } = user;
    }

    5. 访问不存在的数组元素

    问题:

    访问未定义数组的元素会导致错误:

    const arr = undefined;
    const first = arr[0]; // ❌ Runtime Error: Cannot read property '0' of undefined

    解决方案:

  • 解决方案 1:提供默认后备。
  • const first = (arr && arr[0]) || 'Default Value';
  • 解决方案 2:正确初始化数组。
  • const arr = arr || [];
    const first = arr[0];

    6. 数组/函数使用无效

    问题:

    对未定义的值或对象使用诸如 `.map()` 或 `.filter()` 之类的数组方法:

    const numbers = undefined;
    numbers.filter((n) => n > 0); // ❌ Runtime Error: Cannot read property 'filter' of undefined

    解决方案:

  • 解决方案 1:始终验证数组函数的输入。
  • if (Array.isArray(numbers)) {
      numbers.filter(n => n > 0);
    }
  • 解决方案 2:如果输入无效,则返回安全结果。
  • const results = Array.isArray(numbers) ? numbers.filter(n => n > 0) : [];

    7. 条件检查不足

    问题:

    未能严格验证条件可能会导致错误,例如依赖虚假值。例如,`if` 条件期望布尔值可能会错误地评估其他类型,如 `undefined` 或 `0`:

    const obj = {};
    if (obj.prop) {
      // Executes even if obj.prop is `undefined`, leading to unexpected behavior
    }

    解决方案:

  • 解决方案 1:使用严格相等比较。
  • if (obj.prop === true) {
      console.log('Do something');
    }
  • 解决方案 2:明确强制价值观以实现预期行为。
  • if (!!obj.prop) {
      console.log('Do something');
    }
  • 解决方案 3:在代码中定义明确的条件。
  • if (typeof obj.prop === 'boolean' && obj.prop) {
      console.log('Safe conditional execution');
    }

    使用 ESLint 避免不安全的调用

    为了在开发过程中发现这些问题,我们可以利用具有特定规则的 ESLint。下面是一个 ESLint 配置,它将标记不安全的调用并提出修复建议。🛠️🔍🌟

    ESLint 配置

    将以下规则添加到你的 `.eslintrc.js` 或 ESLint 配置文件中:

    module.exports = {
      parser: '@typescript-eslint/parser', // If using TypeScript
      plugins: ['@typescript-eslint'],
      extends: [
        'eslint:recommended',
        'plugin:@typescript-eslint/recommended',
        'plugin:@typescript-eslint/recommended-requiring-type-checking',
      ],
      parserOptions: {
        ecmaVersion: 2020, // or later
        sourceType: 'module',
        project: './tsconfig.json', // Type-aware linting
      },
      rules: {
        // 1. Disallow accessing properties on undefined/null
        '@typescript-eslint/no-unnecessary-condition': 'warn',
    
        // 2. Enforce optional chaining where needed
        'no-unused-expressions': ['warn', { allowShortCircuit: true }],
    
        // 3. Disallow unsafe calls (functions on undefined/null)
        '@typescript-eslint/no-unsafe-call': 'error',
    
        // 4. Disallow unsafe member access (accessing props on undefined/null)
        '@typescript-eslint/no-unsafe-member-access': 'error',
    
        // 5. Catch invalid destructuring of undefined or null
        '@typescript-eslint/no-unnecessary-condition': 'warn',
    
        // 6. Catch invalid array/function usage (e.g., map/filter on undefined)
        'consistent-return': 'warn',
    
        // 7. Enforce stricter conditional checks
        '@typescript-eslint/strict-boolean-expressions': [
          'error',
          {
            allowNullableObject: false,
            allowNullableBoolean: true,
            allowNullableString: true,
            allowNumber: true,
            allowAny: false,
          },
        ],
    
        // Additional rules for clarity and safety:
        'no-implicit-coercion': ['warn', { allow: ['!!'] }],
        'no-unreachable': 'error',
        '@typescript-eslint/no-non-null-assertion': 'error',
      },
    };

    规则说明💡⚙️🌐

  • @typescript-eslint/no-unnecessary-condition:标记不必要的条件或未处理的潜在未定义或空值。⚠️
  • no-unused-expressions:确保除非明确需要,否则避免使用诸如 someObject && someObject.doSomething 之类的短路逻辑。🚀
  • @typescript-eslint/no-unsafe-call:防止对非函数进行不安全的函数调用。❌
  • @typescript-eslint/no-unsafe-member-access:标记尝试访问可能未定义值的属性。✋
  • consistent-return:强制函数中返回类型一致,以避免返回无效或未定义的值。💾
  • @typescript-eslint/strict-boolean-expressions:通过防止隐式强制转换来加强条件表达式。🔒
  • @typescript-eslint/no-non-null-assertion:不允许使用不安全的 ! 运算符来绕过 null/undefined 检查。🚫
  • 安装所需的依赖项📦🔧🔍

    要启用这些规则,请确保安装了必要的 ESLint 插件和解析器:

    npm install eslint @typescript-eslint/parser @typescript-eslint/eslint-plugin --save-dev

    将 ESLint 与 VSCode 集成

    1.安装ESLint扩展:

  • 在 VSCode 市场中搜索“ESLint”并安装。✨
  • 2. 启用自动修复:

    将以下内容添加到您的“settings.json”中:

    {
      "editor.codeActionsOnSave": {
        "source.fixAll.eslint": true
      },
      "eslint.validate": ["javascript", "javascriptreact", "typescript", "typescriptreact"]
    }

    3.运行ESLint:

    添加一个 npm 脚本来运行 ESLint:

    "scripts": {
      "lint": "eslint . --ext .js,.jsx,.ts,.tsx"
    }

    然后,运行 `npm run lint` 来捕获问题。🚀

    结论

    通过实施上述 ESLint 规则和实践,您可以在不安全调用成为运行时错误之前捕获并修复它们。🎉🌈 这种方法将提高您的 JavaScript 和 React 项目的可靠性和可维护性。🌍⚙️✨