This week I released new versions of my RxJS libraries in rxjs-primitives.
Since it's released I've added a few new utility operators. Some of these have been out for a while since I originally wrote about the release, so I've highlighted them here as they may be useful to some developers.
You can check out the full docs here.
Typescript 4
Upgrading to Typescript 4 has allowed the removal of polymorphic functions in place of
Vardic Tuple Types and is why there is a major bump on all packages.
This can be seen in the old and new
concat
operator in the rxjs-string
package.
Most of the tests have also been converted to rxjs-marbles allowing for more robust
Observable testing (if you are working with RxJS I highly recommend checking it out, it integrates well with runners like Jest).
it(
'should return string value of string ending with passed character',
marbles((m) => {
const input = m.hot('-a-b-c-|', { a: 'test', b: 'testing', c: 'gone' });
const subs = '^------!';
const expected = m.cold('---y---|', { y: 'testing' });
m.expect(input.pipe(filterEndsWith('g'))).toBeObservable(expected);
m.expect(input).toHaveSubscriptions(subs);
}),
);
rxjs-array
npm install @tinynodes/rxjs-array
In the array module there are some operators to use with finding
the difference or intersection between a source and a passed array, for example:
of(['a', 'b', 'd'])
.pipe(difference(['a', 'c']))
.subscribe(console.log) // ['b', 'd']
of(['a', 'b', 'd'])
.pipe(intersects(['a', 'c']))
.subscribe(console.log) // ['a']
These methods accept an array, or an Observable<Array>
of items to compare against.
The module also included a binarySearch operator which returns
a custom BinarySearchResult tuple.
rxjs-boolean
npm install @tinynodes/rxjs-boolean
A new Luhn algorithm operator luhnCheck
is provided that does validation on
numbers such as credit cards, ID cards and other value schemes that use the check.
fromString('4485275742308327')
.pipe(luhnCheck())
.subscribe(console.log) // true, this is a valid credit card
rxjs-number
npm install @tinynodes/rxjs-number
inRange
/ outOfRange
and filterInRange
/ filterOutOfRange
both all two numbers, the filter methods return the value from the source observable within the range of those values,
while the other methods return a boolean value if in range. An optional third value will include/exclude the range value
based on the method
fromNumber([-1, 0, 1, 2, 10, 11])
.pipe(filterInRange(0, 10))
.subscribe(console.log) // [0, 1, 2, 10]
// Passing true as the third parameter, the range numbers will also be excluded
fromNumber([-1, 0, 1, 2, 10, 11])
.pipe(filterInRange(0, 10, true))
.subscribe(console.log) // [1, 2]
rxjs-string
npm install @tinynodes/rxjs-string
New operators such as titleize, repeat and
match add new utility features for strings. Where they can they also support localisation:
fromString('Mary had a little lamb')
.pipe(titleize())
.subscribe(console.log) // 'Mary Had A Little Lamb'
fromString('Mary had ä little lamb')
.pipe(titleize('de-DE'))
.subscribe(console.log) // 'Mary Had Ä Little Lamb'
rxjs-utility
npm install @tinynodes/rxjs-utility
The utility module contains some specialised tap operators such as tapIf
, startWithTap
and tapOnSubscribe
.
These provide a way to do side effects. With startWithTap
it can be used with Angular to do a form touch, also tapOnSubscribe
will
fire when there is a subscription to the Observable:
// Only touch on first value change
form.valueChange.pipe(
startWithTap(() => this.onTouch())
).subscribe()
// Fire when a component subscribes to the service bus
this.serviceBus.pipe(
tapOnSubscribe((name: string) => console.log(`New Subscription to ${name}`))
).subscribe()
The tapIf
will only fire if a passed method result is truthy:
fromNumber([1, 2, 3, 4, 5, 6]).pipe(
tapIf((val) => val % 2 === 0), (val) => console.log(val)
).subscribe() // 2, 4, 6
The last operator is mapIfSource
which might be a bit of a weird one but I hope might become useful.
The operator takes the value from the source and passes to a predicate method, and depending on the result will map
the
result of a passed method. A simple example would be:
fromNumber([1, 2, 3, 4, 5, 6]).pipe(
mapIfSource(
(value) => val % 2 === 0,
(value) => val * 10,
(value) => val * 20
)
).subscribe() // 20, 20, 60 40, 100, 60
Here, if the result of the predicate is true multiply by 10, otherwise by 20. The method is typed to allow different return values
based on the result (so you will have to handle the type later). For example we could even turn it into a
FizzBuzz operator:
export function fizzbuzz(): OperatorFunction<number, string | number> {
return (source: Observable<number>) =>
source.pipe(
mapIfSource<number, string, number>(
(value) => value % 15 == 0 || value % 3 == 0 || value % 5 == 0,
(value) => (value % 15 == 0 ? `FizzBuzz` : value % 3 === 0 ? 'Fizz' : 'Buzz'),
(value) => value
)
);
}
// And now we use it in our code
fromNumber([1, 3, 5, 15, 16]).pipe(
fizzbuzz(),
).subscribe() // 1, 'Fizz', 'Buzz', 'FizzBuzz', 16
Hopefully you'll find these operators useful and feel free to leave feedback and suggestions.
Top comments (0)