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
Bug: [prefer-nullish-coalescing] unexpected fails on condition with generics variable which can be null
or undefined
#7842
Comments
In the most technical sense - yes, you are correct - It does seem pretty odd to me that any code written in this manner would be making an intentional and clear distinction between Can you provide a little more context behind the code? Does the distinction matter? |
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
This comment has been minimized.
@bradzacher Consider that I have a class Property<T> {
defaultValue: T;
value: T | undefined; // undefined indicates default fallback
constructor(defaultValue: T) {
this.defaultValue = defaultValue;
}
set(value?: T | undefined) {
this.value = value;
}
get() {
// We focused on this line
return this.value !== undefined ? this.value : this.defaultValue;
}
// ...
} And we can use like this: const httpRequestProperties = {
host: new Property('localhost'),
// Property<string>, which must be set and cannot be null
port: new Property(80),
// Property<number>, which must be set and cannot be null
username: new Property<string | null>('root'),
// Can be null, and null means an empty value (anonymous)
password: new Property<string | null>('p@ssword'),
// Can be null, and null means an empty value (anonymous)
// We should not specify a default value for usernames and passwords, and it's only for demonstration
// ...
} Notice that we explicitly defined the httpRequestProperties.username.set(null);
httpRequestProperties.password.set(null); and this will override their default values, and return However, the code above gets the error:
And if I accept the fix and change to: get() {
return this.value ?? this.defaultValue;
} you may find the logic is broken. I will get An attempt to solve this is to redefine the type of class Property<T> {
defaultValue: T;
value: T | undefined | null; // We add the explicit `null`
// ...
get() {
return this.value !== undefined ? this.value : this.defaultValue;
}
}
const httpRequestProperties = {
host: new Property('localhost'),
// Property<string>, which must be set and cannot be null
// ...
}
const host = httpRequestProperties.host.get();
typeof host // => `string | null`, but it should never be `null` here And I must cast them into the right type manually, in the ungraceful manner. In this situation to my view, I will be happy if you want to fix this, or give any suggestions for this situation. Thank you! |
personally I've found that adding meaning to the distinction between EG: const EMPTY = Symbol();
class Property<T> {
static readonly EMPTY = EMPTY;
defaultValue: T;
value: T | null | typeof EMPTY = EMPTY;
set(value: T | typeof EMPTY) {
this.value = value;
}
get(): T {
return this.value === EMPTY ? this.defaultValue : this.value;
}
} That way you can also support cases like |
Yes, I agree with you and that was what I exactly did to solve this. It's the perfect solution to this situation. But this may have other shortcomings, not easy for serializing, for example. And I personally do not think distinction between Or, could you report another type of rule violate for this case, or add some options to ignore this, as what the |
Although I agree with Brad's points that this is some funky behavior, I also agree that it's technically a bug in the rule 😄. Accepting PRs. Let's have the rule give a more specific error message because I think a lot of people get tripped up on type parameters being allowed to be |
I've noticed a similar issue that's #7055 but with a generic function. Do we need a flag like |
Before You File a Bug Report Please Confirm You Have Done The Following...
Playground Link
https://typescript-eslint.io/play/#ts=5.2.2&fileType=.tsx&code=GYVwdgxgLglg9mABFApgZygHgCoD4AUAbgIYA2AXItogD6LgAmKwMYKDAlIgN4BQiiAE4ooIQUhKlEAQgC8s%2BmCYs2DRAH5EkxJQDkwOHF0BuXgF9evVBnxgQpUh2NA&eslintrc=N4KABGBEBOCuA2BTAzpAXGUEKQAIBcBPABxQGNoBLY-AWhXkoDt8B6Y6RAM0WlqYSNkAC1pkA9gEMkyMswDm6MAG1IvaOOiQAuuDABfEPqA&tsconfig=N4KABGBEDGD2C2AHAlgGwKYCcDyiAuysAdgM6QBcYoEEkJemy0eAcgK6qoDCAFutAGsylBm3TgwAXxCSgA&tokens=false
Repro Code
ESLint Config
tsconfig
Expected Result
I expect there's no errors reported.
Actual Result
I get the following error:
And I get a Fix to nullish coalescing operator (
??
), which changes the logic of the function.Additional Info
If I change the type of
val
toT | undefined | null
, everything goes OK.However, the generic
T
can also benull
. The error does not disappear even if I makeT extends null
. In that situation,val !== undefined ? val : 'foo'
is not equivalent toval ?? 'foo'
and the fix may break the code if I calltest(null)
.The same thing also happens in the following code:
The text was updated successfully, but these errors were encountered: