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
Rule proposal: [prefer-at] Rule to prefer array.at(-1) over array[array.length - 1] #6401
Comments
Why ? 🤔 (sorry 😅) Also, do we want to limit to |
I think we can't guarantee that the function always returns the same array. But it seems to be a rarity. In most cases, it can be replaced with .at(-1). Let's see what others have to say.
Hmm, indeed, if |
Haha, yeah, these very simplified code snippets often look ridiculous. But we have to imagine that sometimes there will be some code somewhere that implements those odd patterns. And if that code is just barely not bizarre enough to be ignored, then we have to consider it as a valid edge case for the rule. In this case, it's not uncommon for people to come from traditional OOP style programming paradigms and write code like: declare class Box<T> {
constructor(private readonly value: T);
getValue(): T;
// maybe some other methods, like updateValue(newValue: T)
}
const box = new Box([Math.random(), Math.random()]);
const lastRandomNumber = box.getValue()[box.getValue().length - 1]; ...but we as the linter might not know that
Yeah makes sense to me! Let's say any constant literal or number after the |
How about creating an option: ignore functions or not? |
I don't think so. It's really hard to generalize whether a codebase has all side-effect-free functions or not, and configuring such an option could easily break code in the future. We should just assume all functions are side-effect-ful, because I don't feel like sane code that's meant to be side-effect-free would be written that way anyway. |
We can just display a warning for functions without autofix. |
Sounds good to me. We can autofix "definitely safe" things (which honestly only includes identifiers, but we can assume member expressions are generally safe as well), while keeping others as suggestions. |
Semantically I think that this rule should be safe to fix through a function call. There really no reasonable code which should look like If you wanted to split hairs about safety: const x = {
get arr() {
return Array(Math.random());
},
};
x.arr[x.arr.length - 1]; Technically it's not safe to fix member expressions due to getters or to proxies! I think we can safely assume that if you call the same function in the indexer and the expression then you're working with the same value. Definitely agree we can add an option to disable that behaviour - but I would expect it to be an opt-out, I.e. Default on, because it's likely the most common case. |
That's exactly what I said with "we can assume member expressions are generally safe" :) But IMO we have to make trade-offs here about what's likely and what's not. |
|
How about this case?
Should it be converted to a: ?
Now - it's being transformed |
@sviat9440 Is that a hypothetical case, or code you've legitimately encountered in the wild? |
It is hypothetical case. It seems that transformation in this case can lead to unexpected results. Especially if we subtract -i instead of -1. |
This code is also correct code that is unsafe to fix: let x = 0;
const arr = [1,2,3];
const lastItem1 = (x += 1, arr)[(x += 1, arr).length - 1];
// or
declare let cond: boolean;
const lastItem2 = (cond ? (cond = !cond, []) : (cond = !cond, arr))[
(cond ? (cond = !cond, []) : (cond = !cond, arr)).length - 1
]; My point is that we could sit here all day dreaming up "semantically correct code a user may write that we shouldn't fix"! The joy of an expression location is that there is literally an infinite number of permutations of code that has side-effects and is semantically correct in the location! My take on this is that we're talking about code that people won't ever write in the real world - so it's not worth the maintenance burden and complexity of handling and testing for them. If someone comes to us with a real world example of their code that they have to write in such an insane style - then, and only then we could consider handling the case (though TBH I'd probably tell them to just use a disable comment...). Otherwise I think we should just "assume good intent" and assume that in the case of |
Before You File a Proposal Please Confirm You Have Done The Following...
My proposal is suitable for this project
Description
#6211 shows a use of
array.at(-1)
, as a cleaner equivalent toarray[array.length - 1]
. https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/atProposal: let's add a typed lint rule that, when it sees something like
array[array.length - 1]
on an Array-typed value, proposes fixing toarray.at(-1)
?Fail Cases
Pass Cases
Additional Info
Reference for an existing similar rule: https://typescript-eslint.io/rules/prefer-includes.
I don't think we should enable this in recommended or strict configs until we only support Node versions that include
.at
. Per #6396 this wouldn't make sense for users who compile to Node 14 and don't include a polyfill.The text was updated successfully, but these errors were encountered: