Description
Before You File a Proposal Please Confirm You Have Done The Following...
- I have searched for related issues and found none that match my proposal.
- I have searched the current rule list and found no rules that match my proposal.
- I have read the FAQ and my problem is not listed.
My proposal is suitable for this project
- I believe my proposal would be useful to the broader TypeScript community (meaning it is not a niche proposal).
Link to the rule's documentation
https://typescript-eslint.io/rules/no-confusing-non-null-assertion/
Description
I propose that the rule should flag on x !instanceof y
and x!instanceof y
(and, also, IMO on x! instanceof y
, but this part is more debatable). I think this a much more confusing nonnull assertion than the one addressed in the existing lint rule.
Fail
declare const x: any;
// logs true if x is a SyntaxError
console.log(x !instanceof SyntaxError);
// logs true if x is a SyntaxError, same AST
console.log(x! instanceof SyntaxError);
// still true 🤮
console.log(x!instanceof SyntaxError);
Pass
declare const x: any;
// logs false if x is a SyntaxError
console.log(!(x instanceof SyntaxError));
Additional Info
I have encountered this twice independently in the wild at work.
The confusion is potentially exacerbated by the fact that in other languages, boolean operators can behave more fluently, for example, in Python:
zero = 0
zero is not False # True, equivalent to not (zero is False)
zero is (not False) # False
so it's intuitive to think that one could write
x !instanceof y
to mean
!(x instanceof y)
and not realize that TS is doing you dirty by permitting that syntax at all (which is not valid JS).
Note that prettier formats to the x! instanceof
form instead of x !instanceof
form. But either way it's yikes.
Playground link for example cases. Note that no-unnecessary-type-assertion doesn't come to the rescue here either.