Skip to content

linter: no-unnecessary-condition false positive on null check of unresolved conditional type #20150

@DreierF

Description

@DreierF

What version of Oxlint are you using?

1.51.0, oxlint-tsgolint 0.16.0

What command did you run?

oxlint

What does your .oxlintrc.json (or oxlint.config.ts) config file look like?

 {
    "plugins": ["typescript"],
    "options": {
      "typeAware": true
    },
    "rules": {
      "@typescript-eslint/no-unnecessary-condition": "error"
    }
  }

What happened?

@typescript-eslint/no-unnecessary-condition reports a false positive when checking value == null on a value whose type is a conditional type that can resolve to include null.

In the example below, Result<T> resolves to string | null when T extends null. Since T is constrained to string | null, the null check is necessary for the T = null case. oxlint does not evaluate the conditional type and reports that Result<T> has no overlap with null.

tsconfig.json:

  {
    "compilerOptions": {
      "module": "ESNext",
      "target": "ES2023",
      "moduleResolution": "bundler",
      "strict": true,
      "noEmit": true,
      "skipLibCheck": true
    },
    "include": ["src"]
  }

src/example.ts:

  type Result<T> = T extends null
    ? string | null
    : T extends string
      ? string
      : T extends boolean
        ? boolean
        : T extends number
          ? number
          : T;

export function processValue<T extends string | null>(value: Result<T>): string {
    if (value == null) {
      return 'default';
    }
    return String(value);
  }

Reported diagnostic:

    x typescript-eslint(no-unnecessary-condition): This condition will always return the same value since the types have no overlap.
      ,-[src/example.ts:12:6]
   11 | function processValue<T extends string | null>(value: Result<T>): string {
   12 |     if (value == null) {
      :         ^^|^^   ^^|^^
      :           |       `-- Type: null
      :           `-- Type: Result<T>
   13 |         return 'default';
      `----

Metadata

Metadata

Assignees

Labels

Type

Projects

No projects

Milestone

No milestone

Relationships

None yet

Development

No branches or pull requests

Issue actions