Skip to content

💅 useExhaustiveSwitchCases misses a union derived from an as const array when imported from another workspace package #12026

Description

@alokn

Environment information

Details
CLI:
  Version:                      2.5.14
Platform:
  CPU Architecture:             aarch64
  OS:                           macos
Environment:
  JS_RUNTIME_NAME:              node
  NODE_PACKAGE_MANAGER:         pnpm/11.24.0
Biome Configuration:
  Status:                       Loaded successfully.
  Path:                         biome.json
  Linter enabled:               true

Rule name

nursery/useExhaustiveSwitchCases

Playground link

Not reproducible in the playground (needs two workspace packages). Full repro below.

What happened?

useExhaustiveSwitchCases does not report a non-exhaustive switch when the discriminant's type is a union derived as (typeof ARR)[number] and imported from another workspace package. The same switch over a locally declared copy of the union is reported. #6929 and #11730 report similar gaps and are closed; this is the workspace-package import case, which still reproduces on 2.5.14.

Repro (pnpm workspace):

package.json                     { "devDependencies": { "@biomejs/biome": "2.5.14" } }
pnpm-workspace.yaml              packages: ["packages/*"]
biome.json                       { "linter": { "enabled": true, "rules": { "nursery": { "useExhaustiveSwitchCases": "error" } } } }
packages/lib/package.json        { "name": "@repro/lib", "version": "1.0.0", "main": "src/index.ts", "types": "src/index.ts" }
packages/app/package.json        { "name": "@repro/app", "version": "1.0.0", "dependencies": { "@repro/lib": "workspace:*" } }

packages/lib/src/index.ts:

export const S = ["a", "b", "c"] as const;
export type S = (typeof S)[number];

packages/app/src/cross.ts (imported union, case "c" missing, no default):

import type { S } from "@repro/lib";

export function f(x: S): number {
  switch (x) {
    case "a":
      return 1;
    case "b":
      return 2;
  }
  return 0;
}

packages/app/src/local.ts (same union declared locally, same missing case):

const L = ["a", "b", "c"] as const;
type L = (typeof L)[number];

export function g(x: L): number {
  switch (x) {
    case "a":
      return 1;
    case "b":
      return 2;
  }
  return 0;
}

Steps: pnpm install, then pnpm exec biome lint packages.

Result: only local.ts is reported (The switch statement is not exhaustive ... These cases are missing: - "c"). pnpm exec biome lint packages/app/src/cross.ts prints Checked 1 file in 2ms. No fixes applied. with no diagnostic.

Expected result

cross.ts is reported with the missing case "c", as local.ts is.

Code of Conduct

  • I agree to follow Biome's Code of Conduct

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-Type-InferenceArea: type inferenceL-JavaScriptLanguage: JavaScript and super languagesS-Bug-confirmedStatus: report has been confirmed as a valid bug

    Type

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions