Skip to content

[no-fallthrough] eslint switch case doesn't respect never #7641

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
4 tasks done
apexskier opened this issue Sep 13, 2023 · 8 comments
Closed
4 tasks done

[no-fallthrough] eslint switch case doesn't respect never #7641

apexskier opened this issue Sep 13, 2023 · 8 comments
Labels
duplicate This issue or pull request already exists enhancement: new base rule extension New base rule extension required to handle a TS specific case package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin

Comments

@apexskier
Copy link

Before You File a Bug Report Please Confirm You Have Done The Following...

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have searched for related issues and found none that matched my issue.
  • I have read the FAQ and my problem is not listed.

Playground Link

https://typescript-eslint.io/play/#ts=5.2.2&fileType=.tsx&code=PTAEFMGcBsEsDsAuBaAJrSBDARtcz5wAPFOQ0AAUQE8AHKAYwCdZaUozFh4B7ZAV3j9I4VMgBumJpABQxWjyaJQAM0ENEsHvAjxI-JuABy4ceCYAKAPqTo-cAC5QhM0wCUTl%2BdABvGaFBEAAsmHgB3Z3AIgFEmUMsAIgBVeCDMeFQ8VFB0SGZYAFsETERRUEEtHQLwAuxzBLcAbhkAXxkZNXgNSsCoRAtMT35a8w9nYbqmX39QSDDYRAYg0AG3aYCAhkwRUABGJz8NjYZtSGVsUABeUATSs4Tmo4DYFRWLy%2Bvbvob1p4DDRAGHS7R5PNp-cB6AzGUzmCzYJqgECgAA8yGQgSC4FAAAMvEwcaAAUDAnRsZD9IZMRhQDTSkwivBMNBVIpMdjOt1tAAaWYIBjY4I05lhTDUSCY0JhWRHcHHbbYgBMTmRaIxQolZ1g0BZoqQEswoGwhkwAGtQDgeGZMTx%2BABzIIzI7Epg6RWguUunQATl9zTaMju-QAzE0gA&eslintrc=N4KABBYEQKYB4BcYDsAmBnKAuMBtckEs6ANgJbIJYBOMAxgPYC2TKqMqUANAYVAA4kArgHMKWAAIIAnvxjo61MvwQBaeeUoB6DRTW1GLNhyi8wAXRABfIA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3TgwAXxCSgA&tokens=false

Repro Code

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export function ensureNever(_value: never): never {
  throw new Error("Unhandled discriminated union member");
}

function test(a: number): number {
  switch (a) {
    case 1: {
      const b = "test";
      if (b == "test") {
        return 1;
      }
      ensureNever(b); // <-- the `never` return type ensure this is terminal for the function, since this always throws
    }
    case 2: // <-- this still wants a break above though
      return 2;
  }
  return 999;
}

test(3);

ESLint Config

{
    "extends": [
      "eslint:recommended",
      "plugin:@typescript-eslint/eslint-recommended"
    ]
}

tsconfig

{
  "compilerOptions": {
    // ...
  }
}

Expected Result

I expect the break statement isn't necessary since the prior case block terminated in an expression returning never (that always throws).

Actual Result

On line 15

Expected a 'break' statement before 'case'.ESLint[no-fallthrough](https://eslint.org/docs/latest/rules/no-fallthrough)

Additional Info

No response

@apexskier apexskier added bug Something isn't working package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Sep 13, 2023
@bradzacher
Copy link
Member

This is expected because the rule is not type-aware. We'd need to build an extension rule.

This is a pretty rare usecase so I'm not sure if it makes sense for us to own and maintain an extension rule for it.

This is the first time in the history of the project that someone has requested this behaviour - so it's either not a common pattern, or just not a common pattern in codebases that use the rule.

The closest issue we've had filed is #3455 (which is similar but A LOT more complicated).

I'll leave this as "evaluating community engagement", but my gut is that we probably won't action this due to how rare it is.

@bradzacher bradzacher added enhancement: new base rule extension New base rule extension required to handle a TS specific case evaluating community engagement we're looking for community engagement on this issue to show that this problem is widely important and removed bug Something isn't working triage Waiting for team members to take a look labels Sep 13, 2023
@apexskier
Copy link
Author

Totally fair. I hadn't see #3455 when I searched, but I'd be okay if you want to close this as duplicate of that.

To add some missed details:

  • I had a vague expectation that "plugin:@typescript-eslint/eslint-recommended" would have disabled/adjusted the failing eslint rule in some way to work around this
  • The main reason I think this is an actually problem is because ts itself actually warns about the break statement I need to add (typescript itself actually conflicts with eslint directly here). If I had stricter typescript compiler warning requirements in my PR checks I'd be forced to actually disable a linting rule.
    startPasswordReset ts — auth-ui - Visual Studio Code - 2023-09-13 at 17 14 17@2x

@bradzacher
Copy link
Member

Yeah for sure - your want makes sense because there's no way to satisfy the lint rule and TS at the same time with code when using this pattern.

But you can satisfy the rule by adding a comment. By default the rule will ignore cases when there is a comment that matches the regex /falls?\s*through/.

I.e. you can add the comment // impossible to fall through due to the above assertion function, and the rule would not error playground.

But this is obviously sub-par in comparison to the rule just working.

@innermatrix
Copy link

@bradzacher fwiw I was just about to file this bug as well, thereby making it half as rare now 🙂

@Eldemarkki
Copy link

Eldemarkki commented Dec 22, 2023

In Next.js there are e.g. redirect("/path") and notFound() which return never. I think this issue affects those cases quite a lot. For example:

function getUserType(): "unauthorized" | "normal" | "admin" {
  return "normal";
}

export default function MyPage() {
  const userType = getUserType();

  switch (userType) {
    case "unauthorized":
      redirect("/login");
      break; // <-- problem here
    case "normal":
      return <div>Welcome, user</div>;
    case "admin":
      return <div>Welcome, admin</div>;
  }
}

With break;:
Unreachable code detected.ts(7027)

Without break;:
Expected a 'break' statement before 'case'.eslintno-fallthrough

Copy link

Uh oh! @Eldemarkki, the image you shared is missing helpful alt text. Check #7641 (comment).

Alt text is an invisible description that helps screen readers describe images to blind or low-vision users. If you are using markdown to display images, add your alt text inside the brackets of the markdown image.

Learn more about alt text at Basic writing and formatting syntax: images on GitHub Docs.

@bradzacher
Copy link
Member

@Eldemarkki your case is easily satisfiable by prefixing it with return

This has the added benefit of also making it very clear that redirect terminates things - which is nice for newbies and when working without intellisense (eg gh reviews)

@bradzacher
Copy link
Member

Duplicate of #3455

@bradzacher bradzacher marked this as a duplicate of #3455 Dec 23, 2023
@bradzacher bradzacher closed this as not planned Won't fix, can't repro, duplicate, stale Dec 23, 2023
@bradzacher bradzacher added duplicate This issue or pull request already exists and removed evaluating community engagement we're looking for community engagement on this issue to show that this problem is widely important labels Dec 23, 2023
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Dec 31, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
duplicate This issue or pull request already exists enhancement: new base rule extension New base rule extension required to handle a TS specific case package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin
Projects
None yet
Development

No branches or pull requests

4 participants
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy