Reasons to not use the mut
helper
-
General problems in the programming model:
- The mut helper is non-intuitive to use, see, teach, and learn since it can either be a getter or a setter based on the context in which it’s used.
Example:
- The need for the no-extra-mut-helper-argument rule is further evidence that
mut
has a non-intuitive signature and frequently gets misused. - The mut helper is usually only used as a pure setter, in which case there are other template helpers that are pure setters that could be used instead of mut (e.g. ember-set-helper).
-
Incompatibility with Glimmer Component intentions:
- The mut helper can re-introduce 2 way data binding into Glimmer Components on named arguments where a child can change a parent’s data, which goes against the Data Down Actions Up principle, goes against Glimmer Components’ intention to have immutable arguments, and is discouraged by the Ember Core team.
Example:
This rule forbids any use of the mut
helper, both as a getter and a setter, in any context. It also
surfaces possible alternatives in the lint violation message to help guide engineers to resolving
the lint violations.
This rule forbids the following:
This rule allows the following:
Coupled with a corresponding JS action to set:
@action
setProfileDescription({ target: { value } }) {
set(this, 'profile.description', value);
}
- When used as a pure setter only,
mut
could be replaced by a JS action ("Option 1" below) or ember-set-helper ("Option 2" below):
Before:
After (Option 1 HBS):
After (Option 1 JS):
@action
setIsDropdownOpen(isDropdownOpen) {
set(this, 'isDropdownOpen', isDropdownOpen);
}
After (Option 2):
2. When used as a pure getter only, mut
could be removed:
Before:
After:
3. When mut
is used as a getter and setter, mut
could be replaced with a different namespace for the property and a dedicated action function to set the property: (Note: another other option could be to pull in the pick helper from ember-composable-helpers and use it like this.) (Note: Another option could be to use ember-box).
Before:
After HBS:
After JS:
@tracked
foo;
@action
updateFoo(evt) {
this.foo = evt.target.value;
// or set(this, ‘foo’, evt.target.value); for legacy Ember code
}
4. When mut
is being passed into a built-in classic component that uses 2 way data binding, mut
could be removed:
Before:
After:
- object -- containing the following properties:
- string --
setterAlternative
-- Optional: String name of a helper that could replace mut as a setter. If configured, the lint violation error message will include this as a possible alternative for resolving the lint violation.
- string --
Example:
// .template-lintrc.js
module.exports = {
rules: {
'no-mut-helper': ['error', {
setterAlternative: '{{set}}',
}]
}
};