Ecosyste.ms: Awesome

An open API service indexing awesome lists of open source software.

Awesome Lists | Featured Topics | Projects

https://github.com/jhusain/eslint-plugin-immutable

ESLint plugin to disable all mutation in JavaScript.
https://github.com/jhusain/eslint-plugin-immutable

Last synced: 7 days ago
JSON representation

ESLint plugin to disable all mutation in JavaScript.

Awesome Lists containing this project

README

        

# eslint-plugin-immutable

This is an ESLint plugin to disable all mutation in JavaScript. Think this is a bit too restrictive? Well if you're using Redux and React, there isn't much reason for your code to be mutating *anything*. Redux maintains a mutable pointer to your immutable application state, and React manages your DOM state. Your components should be stateless functions, translating data into Virtual DOM objects whenever Redux emits a new state. These ESLint rules explicitly prohibit mutation, effectively forcing you to write code very similar to [Elm](http://elm-lang.org/) in React.

## Installing

`npm install eslint-plugin-immutable --save-dev`

## ESLint Rules
There are three rules in the plugin:

### no-let

There's no reason to use `let` in a Redux/React application, because all your state is managed by either Redux or React. Use `const` instead, and avoid state bugs altogether.

```JavaScript
let x = 5; // <- Unexpected let or var, use const.
```

What about `for` loops? Loops can be replaced with the Array methods like `map`, `filter`, and so on. If you find the built-in JS Array methods lacking, use [lodash](https://github.com/lodash/lodash).

```JavaScript
const SearchResults =
({ results }) =>

    {
    results.map(result =>
  • { result }
  • ) // <- Who needs let?
    }
;
```

### no-this

Thanks to libraries like [recompose](https://github.com/acdlite/recompose) and Redux's [React Container components](http://redux.js.org/docs/basics/UsageWithReact.html), there's not much reason to build Components using `React.createClass` or ES6 classes anymore. The `no-this` rule makes this explicit.

```JavaScript
const Message = React.createClass({
render: function() {
return

{ this.props.message }
; // <- no this allowed
}
})
```

Instead of creating classes, you should use React 0.14's [Stateless Functional Components](https://medium.com/@joshblack/stateless-components-in-react-0-14-f9798f8b992d#.t5z2fdit6) and save yourself some keystrokes:

```JavaScript
const Message = ({message}) =>

{ message }
;
```

What about lifecycle methods like `shouldComponentUpdate`? We can use the [recompose](https://github.com/acdlite/recompose) library to apply these optimizations to your Stateless Functional Components. The [recompose](https://github.com/acdlite/recompose) library relies on the fact that your Redux state is immutable to efficiently implement shouldComponentUpdate for you.

```JavaScript
import { pure, onlyUpdateForKeys } from 'recompose';

const Message = ({message}) =>

{ message }
;

// Optimized version of same component, using shallow comparison of props
// Same effect as React's PureRenderMixin
const OptimizedMessage = pure(Message);

// Even more optimized: only updates if specific prop keys have changed
const HyperOptimizedMessage = onlyUpdateForKeys(['message'], Message);
```

### no-mutation

You might think that prohibiting the use of `let` and `var` would eliminate mutation from your JavaScript code. **Wrong.** Turns out that there's a pretty big loophole in `const`...

```JavaScript
const point = { x: 23, y: 44 };
point.x = 99; // This is legal
```

This is why the `no-mutation` rule exists. This rule prevents you from assigning a value to the result of a member expression.

```JavaScript
const point = { x: 23, y: 44 };
point.x = 99; // <- No object mutation allowed.
```

This rule is just as effective as using Object.freeze() to prevent mutations in your Redux reducers. However this rule has **no run-time cost.** A good alternative to object mutation is to use the object spread syntax coming in ES2016.

```JavaScript
const point = { x: 23, y: 44 };
const transformedPoint = { ...point, x: 99 };
```

You can enable this syntax using the [syntax-object-rest-spread](https://babeljs.io/docs/plugins/syntax-object-rest-spread/) [Babel](https://babeljs.io/) plug-in.

## Supplementary ESLint Rules to Enable

The rules in this package alone can not eliminate mutation in your JavaScript programs. To go the distance I suggest you also enable the following built-in ESLint rules:

* no-var (self-explanatory)
* no-undef (prevents assigning to global variables that haven't been declared)
* no-param-reassign (prevents assigning to variables introduced as function parameters)

## Sample Configuration File

Here's a sample ESLint configuration file that activates these rules:

```
{
"extends": "airbnb",
"plugins": [
"immutable"
],
"rules": {
"immutable/no-let": 2,
"immutable/no-this": 2,
"immutable/no-mutation": 2
}
}
```

Special Thanks to [cerealbox](https://github.com/cerealbox) who paired with me on this.