# How to Use withoutCache() to Opt Specific Diagnostics Out of Caching in TSSLint

> Learn when and how to use withoutCache in TSLint to opt specific diagnostics out of caching. Prevent re-evaluation on every lint run.

- Repository: [Johnson Chu/tsslint](https://github.com/johnsoncodehk/tsslint)
- Tags: how-to-guide
- Published: 2026-03-04

---

**Call `.withoutCache()` on the Reporter object returned by `context.report()` to prevent a specific diagnostic from being stored in TSSLint's FileLintCache, ensuring the diagnostic is re-evaluated on every lint run.**

TSSLint is a TypeScript linter that caches diagnostics in memory to speed up incremental linting. However, some diagnostics depend on volatile data or require fresh evaluation every time. The `withoutCache()` method, available on the Reporter object in `johnsoncodehk/tsslint`, allows you to opt specific diagnostics out of this caching mechanism.

## What Is withoutCache() and How Does It Work?

When you call `context.report()` in a TSSLint rule, it returns a **Reporter** object. This object provides chainable methods to modify the diagnostic, including `.withoutCache()`.

According to the source code in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) (lines 281-292), TSSLint maintains an in-memory **FileLintCache** that stores diagnostics between incremental lint runs. When you report a diagnostic, it is automatically pushed into `cache[1][ruleId][1]`. The `.withoutCache()` method looks up this cache entry and **splices** the diagnostic out of the array, ensuring it is not persisted for future runs.

## When to Use withoutCache() in TSSLint Rules

You should use `.withoutCache()` when a diagnostic's validity depends on data that may change between lint runs, or when you explicitly need fresh evaluation every time.

- **Runtime-only dependencies**: Diagnostics based on environment variables, file system state, or external API responses that change independently of source code.
- **Expensive conditional rules**: When a rule is costly to recompute only under specific conditions, but you want the result fresh when those conditions apply.
- **Debug or experimental rules**: Temporary diagnostics that should not pollute the production cache or affect incremental linting performance.
- **Evolving metrics**: Rules that track file-wide statistics which change based on factors outside the AST, requiring re-evaluation on every lint.

If no `FileLintCache` is supplied (for example, when `lint()` is called without a cache object), the `.withoutCache()` call has no effect and acts as a no-op.

## How to Implement withoutCache() in Your Rules

### Basic Usage

Call `.withoutCache()` on the Reporter object returned by `context.report()`:

```typescript
export const noConsoleRule = (ctx: RuleContext) => {
  const { report } = ctx;
  const source = ctx.file.getFullText();
  
  const consoleRegex = /\bconsole\./g;
  let match: RegExpExecArray | null;
  
  while ((match = consoleRegex.exec(source))) {
    report('Avoid using console statements', match.index, match.index + match[0].length)
      .asWarning()
      .withoutCache();  // Prevents this diagnostic from being cached
  }
};

```

### Chaining with Other Modifiers

The `.withoutCache()` method returns the same Reporter instance, allowing you to chain it with other modifiers like `.asError()` or `.withFix()`:

```typescript
report('Unexpected use of eval()', start, end)
  .asError()
  .withFix('Remove eval', () => [{ 
    span: { start, length: end - start }, 
    newText: '' 
  }])
  .withoutCache();  // Skip caching while still offering a fix

```

### Conditional Opt-Out

You can conditionally apply `.withoutCache()` based on runtime conditions:

```typescript
if (process.env.NODE_ENV === 'development') {
  // In dev mode, always re-evaluate this diagnostic
  report('Debug log detected', start, end).withoutCache();
} else {
  report('Debug log detected', start, end);
}

```

## Understanding the Internal Implementation

The `.withoutCache()` method is defined in [`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts) (lines 55-60) as part of the Reporter interface. The actual implementation resides in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) within the `createLinter` function (lines 281-292).

When a diagnostic is reported, the system creates a temporary `cachedObj` reference. If a `FileLintCache` exists, the diagnostic is pushed into `cache[1][ruleId][1]`. The `.withoutCache()` implementation checks for this `cachedObj`, locates the specific rule's cache array, and uses `splice()` to remove the diagnostic entry.

This mechanism ensures that the diagnostic remains in the current lint results (it has already been emitted to the result set) but will not be available for reuse in subsequent incremental lint passes. The CLI worker in [`packages/cli/lib/worker.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/lib/worker.ts) creates and passes the `FileLintCache` to the core linter, while [`packages/cli/lib/cache.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/cli/lib/cache.ts) handles serialization between runs.

## Summary

- **`.withoutCache()`** prevents specific diagnostics from being stored in TSSLint's `FileLintCache`, forcing re-evaluation on every lint run.
- Use it for diagnostics dependent on **runtime data**, **environment variables**, or **external state** that changes independently of source code.
- The method is **chainable** with other Reporter modifiers like `.asError()` and `.withFix()`.
- Internally, it **splices** the diagnostic out of the rule-specific cache array in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) (lines 281-292).
- If no cache is supplied (e.g., non-incremental runs), the call is a **no-op**.

## Frequently Asked Questions

### Does withoutCache() affect the diagnostic output or only the caching?

**`.withoutCache()` only affects the caching mechanism.** The diagnostic is still emitted to the lint results and will appear in the output exactly as if caching were not used. The method simply removes the diagnostic from the `FileLintCache` after it has been reported, ensuring it is not reused in subsequent incremental lint passes.

### Can I use withoutCache() when running TSSLint without incremental caching?

**Yes, but it has no effect.** If you call `lint()` without supplying a `FileLintCache` (for example, in a single-run CLI invocation or custom integration), the `.withoutCache()` method becomes a no-op. It checks for the existence of a cache object before attempting to splice the diagnostic, so it is safe to use unconditionally in rules that may run in both cached and non-cached environments.

### How does withoutCache() interact with other Reporter chain methods?

**`.withoutCache()` returns the same Reporter instance, allowing full chaining.** You can call it before or after other modifiers like `.asError()`, `.asWarning()`, or `.withFix()`. For example, `report('Message', 0, 10).asError().withoutCache().withFix('Fix', fixFn)` works correctly. The order does not affect the final diagnostic output, only the caching behavior.

### Where is the withoutCache() method defined in the TSSLint source code?

**The method signature is defined in [`packages/types/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/types/index.ts) (lines 55-60) as part of the Reporter interface, and implemented in [`packages/core/index.ts`](https://github.com/johnsoncodehk/tsslint/blob/main/packages/core/index.ts) (lines 281-292) within the `createLinter` function.** The implementation handles the logic for splicing diagnostics out of the rule-specific cache array when a `FileLintCache` is present.