RxJS: TSLint Rules for Version 6
April 27, 2018 • 6 minute read
Earlier this week, RxJS version 6 was released and, with its release, managing RxJS imports has become much, much easier.
Last year, I wrote a bunch of TSLint rules for managing RxJS imports. They’re distributed in the rxjs-tslint-rules
package.
Most of the package’s import-related rules are no longer required when linting an RxJS-version-6 codebase, so if the latest release of the rules finds RxJS version 6 installed in node_modules
, the rules that are no longer required are deprecated.
If RxJS version 5 is installed — or if rxjs-compat
is installed alongside RxJS version 6 — the rules will behave as they did in prior releases of the package.
Let’s look briefly at what’s changed and then look at some rules that are still useful for maintaining a clean, RxJS-version-6 codebase.
What’s changed with the imports?
The migration guide discusses all of the changes in detail, but the main, import-related changes can be summarised as follows:
- Classes, types and observable factory functions are imported from
"rxjs"
. - Operators are imported from
"rxjs/operators"
. - Factory functions and operators that patch
Observable
andObservable.prototype
have been removed.
That means that imports like these:
import { Observable } from "rxjs/Observable";
import { concat } from "rxjs/observable/concat";
import { map } from "rxjs/operators/map";
import { take } from "rxjs/operators/take";
Are replaced with imports like these:
import { concat, Observable } from "rxjs";
import { map, take } from "rxjs/operators";
And it means that patching imports like these are no longer supported:
import "rxjs/add/observable/concat";
import "rxjs/add/operator/map";
import "rxjs/add/operator/take";
This greatly simplifies dealing with RxJS imports and renders many of the import-related rules in rxjs-tslint-rules
redundant. Woohoo!
Let’s have look at some rules that are still useful for linting an RxJS-version-6 codebase.
Don’t touch the internals
Even though RxJS version 6 has only just been released and even though everyone knows you shouldn’t touch a package’s internals, I’ve already seen codebases that have imports like this:
import { map } from "rxjs/internals/operators/map";
It’s safe to say that imports that rely upon the package’s internal structure will break, eventually. So if you work with developers that live the YOLO life, you might find the rxjs-no-internal
rule useful.
"rxjs-no-internal": {
"severity": "error"
}
Preparing for further change
RxJS version 6 deprecates a number of library features that will be removed or changed in version 7. In particular:
- the
combineLatest
,concat
,merge
,race
andzip
operators are deprecated in favour of their namesake factory functions; - the result selector parameter accepted by numerous operators is deprecated in favour of using an additional
map
operator; and - some parts of the library have been deprecated for internal use only.
TSLint has a built-in rule that can be used to effect a warning — or an error — if deprecated functionality is used:
"deprecation": {
"severity": "warning"
}
With a large codebase, the number of deprecations can be overwhelming.
If you want to update your codebase in a piecemeal fashion, you can use the rxjs-ban-observables
and rxjs-ban-operators
rules, adding only what you want to ban to the rules’ options.
"rxjs-ban-observables": {
"options": [{
"empty": "Use EMPTY",
"never": "Use NEVER",
}],
"severity": "error"
},
"rxjs-ban-operators": {
"options": [{
"combineLatest": "Use the static combineLatest",
"concat": "Use the static concat",
"merge": "Use the static merge",
"race": "Use the static race",
"zip": "Use the static zip",
}],
"severity": "error"
}
Do you speak Finnish?
Some developers love Finnish notation and some developers loathe it. If you love it, you can enforce its use using the rxjs-finnish
rule:
"rxjs-finnish": {
"severity": "error"
}
By default, the rule will enforce the use of Finnish notation for functions, methods, parameters, properties and variables. If you only want to enforce Finnish notation for, say, variables you can do so using the rule’s options, like this:
"rxjs-finnish": {
"options": [{
"functions": false,
"methods": false,
"parameters": false,
"properties": false,
"variables": true
}],
"severity": "error"
}
If you loathe Finnish notation, you can disallow its use using the rxjs-no-finnish
rule:
"rxjs-no-finnish": {
"severity": "error"
}
Subjects
The package contains a couple of rules that deal with subjects.
The rxjs-no-subject-unsubscribe
can be used to disallow the calling of unsubscribe
on subjects, as calling it can effect some surprising behaviour.(Also, in version 7, the unsubscribe
method is likely to be removed from the Subject
class.)
"rxjs-no-subject-unsubscribe": {
"severity": "error"
}
The rxjs-no-subject-value
rule can be used to disallow the use of a BehaviorSubject
’s value
property — which some developers consider to be a code smell.
"rxjs-no-subject-value": {
"severity": "error"
}
Careful now
The package includes a couple of rules that can help avoid potentially-unsafe practices.
The rxjs-no-unsafe-scope
rule can be used to disallow the accessing or manipulation of state that’s external to a callback function.
"rxjs-no-unsafe-scope": {
"severity": "error"
}
And the rxjs-no-unsafe-switchmap
rule can be used to disallow the use of switchMap
in NgRx effects — and redux-observable
epics — into which it is likely — based on the action type — to introduce race conditions.
"rxjs-no-unsafe-switchmap": {
"severity": "error"
}
Errors
If you’re like me and only want Error
-derived objects to be passed to an observer’s error method, there’s a rule to enforce that:
"rxjs-throw-error": {
"severity": "error"
}
Upgrading from 5 to 6
Another package of RxJS-related TSLint rules — written by some of the developers at Google — was released in conjunction with RxJS version 6: rxjs-tslint
.
Its rules take advantage of TSLint’s automated fixing and can be used to automatically:
- update RxJS imports;
- replace dot-chained operators with pipeable operators; and
- replace static
Observable
method calls with factory function calls.
If you’re updating a codebase from 5 to 6, you should check it out. It’s awesome.