close

no-unused-vars

Added in v0.1.4

Configuration

PresetConfigured Value
✅ ts.configs.recommended["error",{"varsIgnorePattern":"^_","argsIgnorePattern":"^_"}]
✅ ts.configs.recommendedTypeChecked["error",{"varsIgnorePattern":"^_","argsIgnorePattern":"^_"}]
✅ ts.configs.strict["error",{"varsIgnorePattern":"^_","argsIgnorePattern":"^_"}]
✅ ts.configs.strictTypeChecked["error",{"varsIgnorePattern":"^_","argsIgnorePattern":"^_"}]
rslint.config.ts
import { defineConfig, ts } from '@rslint/core';

export default defineConfig([
  ts.configs.recommended,
  {
    rules: {
      '@typescript-eslint/no-unused-vars': 'error',
    },
  },
]);

Rule Details

Disallow unused variables.

Variables, functions, and function parameters that are declared but never used anywhere in the code are most likely an error due to incomplete refactoring. This rule extends the base ESLint no-unused-vars rule with TypeScript-specific awareness:

  • Detects variables that are only used in type contexts (e.g., type annotations) and not in runtime code, reporting them as "defined but only used as a type"
  • Recognizes type-level declarations (interfaces, type aliases, enums) and imports as validly used when referenced in type positions
  • Handles declaration merging (e.g., interface + const with the same name)
  • Respects ambient declarations (declare module, .d.ts files)
  • Marks JSX factory and fragment factory imports as used when JSX elements are present (for jsx: "preserve" / "react-native" modes)

Options

{
  "@typescript-eslint/no-unused-vars": ["error", {
    "vars": "all",                          // "all" | "local"
    "varsIgnorePattern": "",                 // regex pattern for vars to ignore
    "args": "after-used",                   // "after-used" | "all" | "none"
    "argsIgnorePattern": "",                // regex pattern for args to ignore
    "caughtErrors": "all",                  // "all" | "none"
    "caughtErrorsIgnorePattern": "",        // regex pattern for caught errors to ignore
    "destructuredArrayIgnorePattern": "",   // regex pattern for destructured array elements
    "ignoreRestSiblings": false,            // ignore siblings of rest properties
    "ignoreClassWithStaticInitBlock": false, // ignore classes with static init blocks
    "ignoreUsingDeclarations": false,       // ignore `using` / `await using` declarations
    "reportUsedIgnorePattern": false,       // report used vars that match ignore patterns
    "enableAutofixRemoval": {
      "imports": false                      // auto-fix to remove unused imports
    }
  }]
}

Examples of incorrect code for this rule:

const unused = 42;

function foo(unusedParam: string) {
  return 'hello';
}

import { SomeValue } from './values';
const x: number = getSomething(); // SomeValue is never used

Examples of correct code for this rule:

const used = 42;
console.log(used);

export function foo() {}

function bar(_unused: string, used: number) {
  return used;
}

// Type-only usage of imports is valid
import { SomeType } from './types';
const x: SomeType = getValue();

// Ignore pattern: variables starting with _ are ignored
function baz(_unused: string) {}

The /* exported */ comment

A script shares its globals with the other scripts loaded alongside it, where this rule cannot see them being read. An /* exported name */ block comment declares that such a global is consumed elsewhere, and the rule counts the comment itself as a use. TypeScript's scope manager puts type-only declarations in the same global scope as value ones, so the comment reaches an interface, type, enum, or namespace as well:

/* exported PublicValue, PublicType */
var PublicValue = 1;
type PublicType = string;

The comment resolves each name only against the outer global scope. Whether a file has that scope is determined by its effective languageOptions.sourceType, not by the presence of import or export syntax. With flat config, omitting sourceType makes .js and .ts files modules even when they contain no module syntax, so the comment has no effect. Set sourceType: "script" for a shared script.

Module bindings, bindings in a JavaScript CommonJS wrapper, block bindings, function parameters, and nested type bindings are still reported. An exact, case-sensitive .cjs extension defaults to the CommonJS wrapper. TypeScript-flavoured files configured as commonjs retain a global program scope, so their top-level bindings can be marked by the comment.

Original Documentation