Thanks to visit codestin.com
Credit goes to github.com

Skip to content

[strict-boolean-expressions] False positive when using union types #2894

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
3 tasks done
eamodio opened this issue Dec 22, 2020 · 10 comments
Closed
3 tasks done

[strict-boolean-expressions] False positive when using union types #2894

eamodio opened this issue Dec 22, 2020 · 10 comments
Labels
enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin working as intended Issues that are closed as they are working as intended

Comments

@eamodio
Copy link

eamodio commented Dec 22, 2020

  • I have tried restarting my IDE and the issue persists.
  • I have updated to the latest version of the packages.
  • I have read the FAQ and my problem is not listed.

Repro

{
  "rules": {
    "@typescript-eslint/strict-boolean-expressions": [
      "warn",
      {
	"allowString": true,
	"allowNumber": true,
	"allowNullableObject": true,
	"allowNullableBoolean": true,
	"allowNullableNumber": false,
	"allowNullableString": true,
	"allowAny": false
      }
    ],
  }
}
function foo(value?: boolean | { prop: any }) {
	if (value) {
		// value above errors with "Unexpected value in conditional. A boolean expression is required."
	}
}

tsconfig.json

{
	"compilerOptions": {
		"esModuleInterop": true,
		"experimentalDecorators": true,
		"forceConsistentCasingInFileNames": true,
		"incremental": true,
		"isolatedModules": true,
		"lib": ["es2019"],
		"module": "esnext",
		"moduleResolution": "node",
		"noFallthroughCasesInSwitch": true,
		"noImplicitReturns": true,
		"noUnusedLocals": false,
		"outDir": "dist",
		"resolveJsonModule": true,
		"rootDir": "src",
		"skipLibCheck": true,
		"sourceMap": true,
		"strict": true,
		"target": "es2019"
	}
}

Expected Result

No error on the if (value) { line

Actual Result

"Unexpected value in conditional. A boolean expression is required." on the if (value) { line

Versions

package version
@typescript-eslint/eslint-plugin 4.10.0
@typescript-eslint/parser 4.10.0
TypeScript 4.0.5
ESLint 7.16.0
node 12.16.2
@eamodio eamodio added package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin triage Waiting for team members to take a look labels Dec 22, 2020
@bradzacher
Copy link
Member

Right now this is "working as intended"
The rule is built around the idea of reducing the number of truthy/falsy states that are evaluated in a condition.

if (boolean | object | undefined) {} has:

  • 2 truthy states:
    • true
    • object
  • 2 falsey states:
    • false
    • undefined

With your options - you've specified that you don't care about the undefined case (eg for the purposes of the rule, there's only 1 falsey case).
However this means we still have 2 truthy states.

Which begs the question: "is true intentionally treated the same as object exists?"
They're distinct values - do they mean the same thing logically?

The question is - how should we handle this?
What's the correct behaviour? From a strictness / case handling POV - the rule is correct in flagging this.
From a user's perspective - I can definitely understand how this is a surprising result.

@bradzacher bradzacher added awaiting response Issues waiting for a reply from the OP or another party and removed triage Waiting for team members to take a look labels Dec 22, 2020
@eamodio
Copy link
Author

eamodio commented Dec 22, 2020

Yeah, I definitely come down on the user's side on this one 😉 Mainly because given the settings, if the value were either of the two truthy states it would be allowed, so I would want the combination to be allowed. But if extra strictness is desire/required, maybe have a strictUnions option or something that would opt into that behavior?

@phaux
Copy link
Contributor

phaux commented Dec 25, 2020

It works fine in this case. This rule is all about being explicit. You should write your condition as something like value != undefined && value !== false and it should work. The whole reason for this rule is to make the conditions explicit about what values they check.

@bradzacher bradzacher added enhancement: plugin rule option New rule option for an existing eslint-plugin rule and removed awaiting response Issues waiting for a reply from the OP or another party labels Feb 18, 2021
@aaronadamsCA

This comment was marked as resolved.

@bradzacher
Copy link
Member

Try using != null. It's shorter, understood by TS and clear to developers.

children != null && <div>{children}</div>

At Facebook the entire codebase exclusively uses == null checks because in flow there is the "maybe" operator (?boolean means boolean | null | undefined). Because of the operator we never annotate | null manually, so we always have to check for undefined in code. IMO it's a huge improvement in coding style.

@aaronadamsCA
Copy link

Thanks, that's interesting; so it sounds like you don't enforce triple-equals in TS. That makes sense; I hadn't even considered that eqeqeq ceases to be a useful rule once you've got all these TS rules up and running in their place. I'm definitely going to give that a try.

@bradzacher
Copy link
Member

so it sounds like you don't enforce triple-equals in TS.

On the contrary - eqeqeq is enabled, but we have the option turned on which allows you to use double equals specifically for comparisons with null

See the end of this section: https://eslint.org/docs/rules/eqeqeq#always

"eqeqeq": ["error", "always", {"null": "ignore"}],

@aaronadamsCA
Copy link

aaronadamsCA commented Aug 23, 2021

Wow, that is 1000x better than what I was doing, thank you!

Edit: "eqeqeq": ["error", "smart"] is great as well.

@phaux
Copy link
Contributor

phaux commented Aug 19, 2022

I believe this issue can be closed

@JoshuaKGoldberg JoshuaKGoldberg added triage Waiting for team members to take a look and removed accepting prs Go ahead, send a pull request that resolves this issue labels Aug 19, 2022
@JoshuaKGoldberg
Copy link
Member

Indeed. I think the rule is working as intended, as previously mentioned. There are two falsy cases in type boolean | { prop: any } | undefined; the intent of the rule is to stop checks on them from happening.

One could make an argument that the combination of allowNullableBoolean and allowNullableObject should stop that case, but each argument on its own is only meant to target a type union of just that type + nullable.

Marking this as working-as-intended because of all that, and that there's been very little activity on this issue in the almost 2 years it's been open. Feel free to post back or make a new issue if you think this is incorrect! Thanks all!

@JoshuaKGoldberg JoshuaKGoldberg added working as intended Issues that are closed as they are working as intended and removed triage Waiting for team members to take a look labels Aug 23, 2022
@github-actions github-actions bot locked as resolved and limited conversation to collaborators Sep 23, 2022
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
enhancement: plugin rule option New rule option for an existing eslint-plugin rule package: eslint-plugin Issues related to @typescript-eslint/eslint-plugin working as intended Issues that are closed as they are working as intended
Projects
None yet
Development

No branches or pull requests

5 participants