Skip to content

💅 noUnnecessaryConditions: false positive when a literal-initialised object property is mutated #11174

Description

@XXMOHAMED012

Environment information

CLI:
Version: 2.5.6
Color support: false

Platform:
CPU Architecture: x86_64
OS: windows

Environment:
BIOME_DISTRIBUTION: npm
BIOME_LOG_PATH: unset
BIOME_LOG_PREFIX_NAME: unset
BIOME_LOG_LEVEL: unset
BIOME_LOG_KIND: unset
BIOME_CONFIG_PATH: unset
BIOME_THREADS: unset
BIOME_WATCHER_KIND: unset
BIOME_WATCHER_POLLING_INTERVAL: unset
NO_COLOR: 1
TERM: unset
JS_RUNTIME_VERSION: v24.16.0
JS_RUNTIME_NAME: node
NODE_PACKAGE_MANAGER: bun/1.3.14

Biome Configuration:
Status: Loaded successfully.
Path: biome.json
Formatter enabled: true
Linter enabled: true
Assist enabled: true
VCS enabled: false
HTML full support enabled: unset

Linter:
JavaScript enabled: unset
JSON enabled: unset
CSS enabled: unset
GraphQL enabled: unset
Recommended: unset
Enabled rules:
suspicious/noUnnecessaryConditions

Workspace:
Open Documents: 0

Rule name

suspicious/noUnnecessaryConditions

Playground link

https://biomejs.dev/playground/?lintRules=all&tab=diagnostics&code=YwBvAG4AcwB0ACAAZwB1AGEAcgBkACAAPQAgAHsAIABjAHUAcgByAGUAbgB0ADoAIABmAGEAbABzAGUAIAB9ADsACgAKAGUAeABwAG8AcgB0ACAAZgB1AG4AYwB0AGkAbwBuACAAcgB1AG4ATwBuAGMAZQAoACkAIAB7AAoACQBpAGYAIAAoAGcAdQBhAHIAZAAuAGMAdQByAHIAZQBuAHQAKQAgAHsACgAJAAkAcgBlAHQAdQByAG4AOwAKAAkAfQAKAAkAZwB1AGEAcgBkAC4AYwB1AHIAcgBlAG4AdAAgAD0AIAB0AHIAdQBlADsACgB9AAoACgAvAC8AIABDAG8AbgB0AHIAbwBsADoAIAB0AGgAZQAgAHMAYQBtAGUAIABsAG8AZwBpAGMAIABvAG4AIABhACAAYgBpAG4AZABpAG4AZwAgAHIAYQB0AGgAZQByACAAdABoAGEAbgAgAGEAIABwAHIAbwBwAGUAcgB0AHkAIABpAHMAIABuAG8AdAAgAGYAbABhAGcAZwBlAGQALgAKAGwAZQB0ACAAZgBsAGEAZwAgAD0AIABmAGEAbABzAGUAOwAKAAoAZQB4AHAAbwByAHQAIABmAHUAbgBjAHQAaQBvAG4AIAByAHUAbgBPAG4AYwBlAEIAaQBuAGQAaQBuAGcAKAApACAAewAKAAkAaQBmACAAKABmAGwAYQBnACkAIAB7AAoACQAJAHIAZQB0AHUAcgBuADsACgAJAH0ACgAJAGYAbABhAGcAIAA9ACAAdAByAHUAZQA7AAoAfQAKAA%3D%3D

Expected result

No diagnostic should be emitted on line 4. guard.current is assigned true on line 7, so the condition is reachable.

Reproduction

const guard = { current: false };

export function runOnce() {
    if (guard.current) {   // <-- "This condition is always falsy."
        return;
    }
    guard.current = true;
}

// Control: the same logic on a binding rather than a property is not flagged.
let flag = false;

export function runOnceBinding() {
    if (flag) {
        return;
    }
    flag = true;
}

biome lint on 2.5.6, with suspicious/noUnnecessaryConditions as the only enabled rule:

repro.ts:4:6 lint/suspicious/noUnnecessaryConditions ━━━━━━━━━━━━━━━━━━━━━━━━━━

  × This condition is always falsy.

    3 │ export function runOnce() {
  > 4 │     if (guard.current) {
      │         ^^^^^^^^^^^^^
    5 │         return;
    6 │     }

  i The value's type can never be truthy, so this check is redundant.

Found 1 error.

Analysis

The property keeps the literal type false from its initialiser, and the later assignment is not taken into account. The control case in the same file shows the asymmetry: the mutation exemption added in #10108 covers plain bindings, but not member expressions. TypeScript widens the property to boolean here and reports nothing.

Other shapes that reproduce

  • const r = useRef(false); … r.current = true — this is the common React in-flight guard against double submission, and it is where I hit the false positive in real code.
  • const r = useRef<boolean>(false) — an explicit type argument does not help; the initialiser still wins.
  • const r = useRef(0); … r.current = 1 — same behaviour, reported as always falsy.
  • const r = useRef(true); … r.current = false — reported as always truthy.

An as cast on the initialiser (useRef(false as boolean)) silences it, which is consistent with the literal type being the cause.

Impact

The reported code is not redundant, so acting on the diagnostic removes a working guard. There is no safe automatic fix; the only option today is a biome-ignore comment on every such condition.

Code of Conduct

  • I agree to follow Biome's Code of Conduct

Metadata

Metadata

Assignees

No one assigned

    Labels

    S-Needs responseStatus: await response from OPS-Needs triageStatus: this issue needs to be triaged

    Type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions