-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
feat(eslint-plugin): [no-unsafe-array-reduce] Add rule #1779
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
feat(eslint-plugin): [no-unsafe-array-reduce] Add rule #1779
Conversation
Add rule for protecting against unsafe array reduce calls. The type of {} is {}. Any object is assignable to {}. {} is assignable to any indexed type (`{[key in string]: whatever}`) A reduce call with an empty object initializer and no type signature, will infer the {} type for the accumulator and result of the reduce expression. Since anything is assignable to {}, this means the reduce function is essentially unchecked. The result of the expression can then also be assigned to an incompatible type without raising any errors. This rule warns if a reduce call takes an empty object as the initial value and has no type signatures.
Thanks for the PR, @asmundg! typescript-eslint is a 100% community driven project, and we are incredibly grateful that you are contributing to that community. The core maintainers work on this in their personal time, so please understand that it may not be possible for them to review your work immediately. Thanks again! 🙏 Please, if you or your company is finding typescript-eslint valuable, help us sustain the project by sponsoring it transparently on https://opencollective.com/typescript-eslint. As a thank you, your profile/company logo will be added to our main README which receives thousands of unique visitors per day. |
Codecov Report
@@ Coverage Diff @@
## master #1779 +/- ##
==========================================
- Coverage 95.20% 95.00% -0.21%
==========================================
Files 148 159 +11
Lines 6989 7080 +91
Branches 2017 2021 +4
==========================================
+ Hits 6654 6726 +72
- Misses 124 154 +30
+ Partials 211 200 -11
|
I'm curious what the motivation behind this rule is. const x = ['a'].reduce((acc, cur) => acc[cur], {});
// ^^^^^^^^
// Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '{}'.
// No index signature with a parameter of type 'string' was found on type '{}'.(7053) Additionally, It seems fairly safe without a lint rule. |
See https://www.typescriptlang.org/play/index.html#code/MYewdgzgLgBAZiEAuGBvGBtA1gUwJ4wCWYM0ATsQOYC6A-CuVTAL4wC8mARLnp9QHRkcAEwCuwHAApJAQ2DAANDGCiyASnYA+GJPT99cxZhVlqKAIws1S1MzUAoewHonMAEqiSUQgFscMABU8AAccAFEyMhAyewQQfh5afmgZMigIAHVCKAALSU5ONSA for a minimal example of how untyped reduce with a You're right that you can't read indexes of the #1707 is related, but it deals with where the type argument is provided. Which seems like more of an aesthetic issue than requiring there to be a type argument like we do here. |
I don't think creating a rule that just handles the case of an array reduce is a good solution to this, as this can happen in more places than just a reduce. let x: {} = {};
x = { ...x, a: 1 };
const y: Record<string, string> = x; The specific problem here is that |
I agree in principle. This is reduce-oriented since
If you have some pointers on 2. that's definitely something worth looking into. :) |
Sorry, this got lost in my notifications. This could actually live in the |
Add rule for protecting against unsafe array reduce calls.
The type of
{}
is{}
. Any object is assignable to{}
.{}
is assignable toany indexed type (
{[key in string]: whatever}
).A reduce call with an empty object initializer and no type signature,
will infer the
{}
type for the accumulator and result of the reduceexpression. Since anything is assignable to
{}
, this means the reducefunction is essentially unchecked. The result of the expression can then
also be assigned to an incompatible type without raising any errors.
This rule warns if a reduce call takes an empty object as the initial
value and has no type signatures.