-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
Documentation: is no-unnecessary-condition
really a looser alternative to strict-boolean-expressions
?
#1016
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
Comments
Yeah I accepted no-unnecessary-condition because it was just different enough to strict-boolean-expressions to make it a headache to merge them. Part of me feels like these two rules could be merged into one with a lot of configurability. Though at the same time sometimes it is nice to have rules that just work and have zero config. I really hope that typescript will build some of this in as compiler checks in the future |
I think keeping them separated is better. A small intersection isn't really an issue, since they are reported for different reasons. They are quite different conceptually,
At least for me it's a lot easier to configure few simple rules than a single complex one.
I wouldn't expect it any time soon. All of TypeScript's options are designed in a way that you want to have all of them enabled once your code is typed well. But these rules are different, because even if your code is perfectly-typed you may still have to do useless for type system checks, since declarations you're consuming are usually not perfect. For example, even TypeScript has some incorrect types (microsoft/TypeScript#24706). |
Looks like you have accidentally sent your first message the second time? |
uh. sorry - github borked because I hit comment and closed my laptop straight away.
Yeah and it has caused us a number of bugs because of it. No good having types if they're purposely wrong.... I would like to see some of it be added as a compiler option, considering flow has "sketchy null" checks built into the compiler (which covers most of strict-boolean-expressions).
definitely. It's about finding the right balance between small individual rules and rules that don't overlap. The hope is that you never introduce a rule that can get the user into a state where they have conflicting error messages. |
I spent a fair bit of time thinking about my "looser"/"stronger" wording. I knew when I wrote it wasn't strictly true - there are some cases that But I found few enough cases that weren't either caught by But the core difference between the rules - and the main reason I'd argue against merging them - is that strict-boolean-expressions is largely a stylistic rule - avoiding "truthy/falsy" conditions is a particular JS coding style - while Maybe "more opinionated"/"less opinionated" is a better comparison of the rules? |
TS does have some of this as compiler checks, for example: const foo = "foo";
const bar = "bar";
if(foo === bar) {} // ERROR: condition is always false, since "foo" does not overlap with "bar" which is the exact same logic that this linter rule is doing. But the problem with compiler checks is there's no good way to handle false positives. There's no equivalent to And there's a decent number of valid false positives with the more in-depth checking that this rule does. I found two major categories:
function hasRequiredParam(array: string[]) {
// Throw an error for the plebeians without type checking
if(!array) throw new Error("Function requires an array");
}
type Foo = {foo: () => string}
function example(array: Foo[]) {
// According to the types `array[0]` is `Foo`, but in reality it could be `Foo | undefined`.
// So this check is necessary, but doesn't appear to be, based on the types.
// Same issue happens with object index signatures.
if(array[0]) {
return array[0].foo();
}
} This is unfortunate, but lint rules are designed to deal with false-positives like this. But I don't think the compiler wants to get in the business of false-positive results; so I doubt that it's going to put "no-unnecessary-condition"s out of business anytime soon... (as awesome as that would be). |
In the 2nd case, couldn't you just type the array as |
@glen-84 That would force you to check for undefined when indexing the array, but it makes everything else more difficult: you can't pass it to thing expecting const array = [1,3,5] as Array<number | undefined>;
const res = array.map(x => { /* x is `number | undefined`, should be `number` */ }); I do find it's generally fairly reasonable to type "dictionary" objects as something like // All these are largely equivalent
type T1 = Record<string, Foo | undefined>
type T2 = Partial<Record<string, Foo>>
type T3 = {[key: string]: Foo | undefined}
type T4 = {[key in string]?: Foo} I haven't found major drawbacks to this approach, (except some general bloat to typings); so this is how I fixed a lot of the false positives from applying |
Currently in documentation of these rules there are these lines:
Which generally implies that when
strict-boolean-expression
is enabled there is no need forno-unnecessary-condition
.There is indeed some intersection:
However
strict-boolean-expressions
just makes sure that condition is written clearly, it doesn't check that it actually can be true:The text was updated successfully, but these errors were encountered: