-
-
Notifications
You must be signed in to change notification settings - Fork 292
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
Enable no-param-assign
in esnext
?
#368
Comments
This would be very nice! Modifying the user supplied object is a very common mistake. I made it in the past very often and probably will be in the future as well. It's very easily overlooked. |
I'm all for it, as I prefer to do something like this anyway: functino foo(_bar) {
var bar = _bar || {};
// ...
} Wanting to wait for some version of Node to end/start/celebrate a birthday is always tricky though IMO, and I don't have a good solution for it. Most of the modules you and I build run on active/in maintenance versions of Node.js, and if possible, I'd like them to keep working for all "in maintenance" versions. |
Wow. Did not know that. So yeah, 👍. For non- |
Personally don't care about the arguments object thing. The important part for me is to protect about modifying user supplied objects, like options. I also don't think it's worth doing a plugin. In a year we'll be targeting Node.js 6 and can use default arguments, even earlier for CLI tools.
That's why we have the |
OK, is there a way to have it just be about modifying a properties of an object? (and ignore the param reassignment part)? Because this really applies even without |
@jamestalmage No, that's why I initially didn't add it here. The |
This rule will be problematic for cases like the following though: module.exports = foo => {
if (typeof foo === 'string' || Buffer.isBuffer(foo)) {
foo = doSomething(foo);
}
return doSomethingMore(foo);
}; I know I can define a variable at the top and assign to it, but feels like a lot of boilerplate. Any suggestions? |
You could wrap it in another function function doSomethingIfNeeded(foo) {
if (typeof foo === 'string' || Buffer.isBuffer(foo)) {
return doSomething(foo);
}
return foo;
}
module.exports = foo => doSomethingMore(doSomethingIfNeeded(foo)) |
That would be my vote on how to handle it. @jfmengels suggestion is nice, but also feels like boilerplate. If we were to go ahead with this, I would like the rule to have some of the following behaviors: export default function (foo, bar) {
foo = foo || {}; // allowed
bar = processInput(bar); // allowed
foo.baz = 'something'; // error - foo *might* not have been reassigned.
bar.quz = 'something'; // allowed - we assume processInput returns a safe copy
}
// rule only applies to exported functions
export function recursive(input) {
recurse(input, {stack: []});
}
function recurse(input, state) {
// not exported, so `state` can be manipulated.
state.foo = 'bar';
// this is bad, but much harder to detect. I propose we punt on it for the first iteration.
input.foo = 'baz';
} The As a second milestone we could expand the rule to track reassignment that occurs in non-exported functions: // It is exported, so both inputs - are marked as user supplied objects.
export default function(foo, bar) {
foo = Object.assign({}, foo); // foo is unmarked - we no longer care what other functions do to it.
internal(foo, bar); // we check if `internal` treats `bar` safely - warning if it does not.
}
// We perform same analysis on `internal` function
// We collect metadata about which parameters it treats "nicely".
function internal(foo, bar) {
} Finally, we could go nuts and analyze the contents of imported functions, checking how "nicely" they handle parameters passed to them. (Maybe just assume imports from This last idea (and the |
I agree with The part about what's exported and not sounds a bit fragile and complicated. Even if you're working on an internal object, should you really mutate it? Nested mutations makes code so much harder to read and reason about, even if internal. |
@jamestalmage Can you move your last paragraph to #104, so we can discuss there instead? I really want something like that, that can do deeper analysis where speed is unimportant. Something I can run once in awhile. |
I enabled this in Tidy, my own It ended up with a lot of my code looking like: const foo = (option) => {
const config = Object.assign({}, option);
// ...
}; ... even when it isn't strictly necessary, which annoyed me at first. But then later when I wanted to add defaults or overrides it was so pleasing to have that pattern already in place. BTW... module.exports = foo => {
return doSomethingMore(
typeof foo === 'string' || Buffer.isBuffer(foo) ?
doSomething(foo) :
foo
);
}; |
http://eslint.org/docs/rules/no-param-reassign with
{props: true}
option.It's useful to prevent mistakes like modifying the user supplied object (which I still manage to do...).
I've not enabled the rule yet as it's useful to be able to do
foo = foo || {}
, but with default arguments in Node.js 6, this will no longer be needed.I would like to enable this on
esnext
when Node.js 6 has been out for a while.@jamestalmage @jfmengels @vdemedes Thoughts?
Relevant: eslint/eslint#2770
The text was updated successfully, but these errors were encountered: