Skip to content

Commit

Permalink
feat: add ofType operator
Browse files Browse the repository at this point in the history
closes #11
  • Loading branch information
Mohammad Hasani committed Feb 14, 2019
1 parent d8c85f0 commit 63fb590
Show file tree
Hide file tree
Showing 8 changed files with 173 additions and 0 deletions.
2 changes: 2 additions & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -27,6 +27,7 @@
"clean": "rimraf tmp dist coverage"
},
"dependencies": {
"rxjs": "^6.3.3",
"tslib": "^1.9.3"
},
"devDependencies": {
Expand All @@ -53,6 +54,7 @@
"rollup-plugin-sizes": "^0.4.2",
"rollup-plugin-sourcemaps": "^0.4.2",
"rollup-plugin-terser": "^4.0.2",
"rxjs-marbles": "^5.0.0",
"semantic-release": "^15.13.3",
"ts-jest": "^23.10.5",
"tslint": "^5.12.1",
Expand Down
1 change: 1 addition & 0 deletions src/__tests__/__snapshots__/index.spec.ts.snap
Original file line number Diff line number Diff line change
Expand Up @@ -6,5 +6,6 @@ Object {
"createAction": [Function],
"createReducer": [Function],
"getType": [Function],
"ofType": [Function],
}
`;
13 changes: 13 additions & 0 deletions src/__tests__/__snapshots__/of-type.dts.spec.ts.snap
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
// Jest Snapshot v1, https://goo.gl/fbAQLP

exports[`ofType of(a(), b(), c()).pipe(ofType('a')) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType('a')) 1`] = `"Observable<{ type: \\"a\\"; } | { type: \\"b\\"; } | { type: \\"c\\"; }>"`;

exports[`ofType of(a(), b(), c()).pipe(ofType(['a', 'b'])) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType(['a', 'b'])) 1`] = `"Observable<{ type: \\"a\\"; } | { type: \\"b\\"; } | { type: \\"c\\"; }>"`;

exports[`ofType of(a(), b(), c()).pipe(ofType([a(), b()])) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType([a(), b()])) 1`] = `"Observable<{ type: \\"a\\"; } | { type: \\"b\\"; }>"`;

exports[`ofType of(a(), b(), c()).pipe(ofType([a, b])) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType([a, b])) 1`] = `"Observable<{ type: \\"a\\"; } | { type: \\"b\\"; }>"`;

exports[`ofType of(a(), b(), c()).pipe(ofType(a())) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType(a())) 1`] = `"Observable<{ type: \\"a\\"; }>"`;

exports[`ofType of(a(), b(), c()).pipe(ofType(a)) (type) should match snapshot: ofType of(a(), b(), c()).pipe(ofType(a)) 1`] = `"Observable<{ type: \\"a\\"; }>"`;
28 changes: 28 additions & 0 deletions src/__tests__/of-type.dts.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
import { of } from 'rxjs'

import { createAction } from '../create-action'
import { ofType } from '../of-type'

// @dts-jest:group ofType

const a = createAction('a')
const b = createAction('b')
const c = createAction('c')

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType(a))

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType([a, b]))

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType(a()))

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType([a(), b()]))

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType('a'))

// @dts-jest:pass:snap
of(a(), b(), c()).pipe(ofType(['a', 'b']))
80 changes: 80 additions & 0 deletions src/__tests__/of-type.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,80 @@
import { marbles } from 'rxjs-marbles/jest'

import { createAction } from '../create-action'
import { ofType } from '../of-type'

describe('ofType', () => {
const a = createAction('a')
const b = createAction('b')
const c = createAction('c')
const d = createAction('d')
const e = createAction('e')
const f = createAction('f')
const g = createAction('g')
const h = createAction('h')

const values = {
a: a(),
b: b(),
c: c(),
d: d(),
e: e(),
f: f(),
g: g(),
h: h(),
}

const test = ({ action, subs, expected, keys }: any) =>
marbles(m => {
const action$ = m.hot(action, values)
const expected$ = m.cold(expected, values)

m.expect(action$.pipe(ofType(keys))).toBeObservable(expected$)
m.expect(action$).toHaveSubscriptions(subs)
})()

it.each([
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c-----------c-----|',
keys: c,
},
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c--d-----f--c-----|',
keys: [c, d, f],
},
])('should filter in with action creator(s)', test)

it.each([
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c-----------c-----|',
keys: c(),
},
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c--d-----f--c-----|',
keys: [c(), d(), f()],
},
])('should filter in with action(s)', test)

it.each([
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c-----------c-----|',
keys: 'c',
},
{
action: ' -a--b-^-c--d--e--f--c--h--|',
subs: ' ^-------------------!',
expected: ' --c--d-----f--c-----|',
keys: ['c', 'd', 'f'],
},
])('should filter in with action type(s)', test)
})
1 change: 1 addition & 0 deletions src/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,4 @@ export { action, Action, AnyAction } from './action'
export { createAction, ActionCreator } from './create-action'
export { getType } from './get-type'
export { createReducer } from './create-reducer'
export { ofType } from './of-type'
36 changes: 36 additions & 0 deletions src/of-type.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { filter } from 'rxjs/operators'

import { ActionCreator } from './create-action'
import { AnyAction } from './action'
import { getType } from './get-type'

/**
* Filter actions emitted by the source Observable by only emitting those that
* are compatible with specified action(s) or action creator(s) or action type(s).
*
* @example
* action$.pipe(
* ofType(foo),
* ...
* )
* @example
* action$.pipe(
* ofType([foo, bar]),
* ...
* )
*/
export function ofType<
Source extends AnyAction,
Key extends ActionCreator<Source> | Source | Source['type'],
Sink extends Source = Key extends (...args: any[]) => infer U
? (U extends Source ? U : never)
: (Key extends Source ? Key : never)
>(keys: Key | Key[]) {
const types: string[] = (Array.isArray(keys) ? keys : [keys]).map(key =>
typeof key === 'string' ? key : getType(key)
)

return filter<Source, Sink>(
(action): action is Sink => types.includes(action.type)
)
}
12 changes: 12 additions & 0 deletions yarn.lock
Original file line number Diff line number Diff line change
Expand Up @@ -2265,6 +2265,11 @@ fast-deep-equal@^2.0.1:
resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz#7b05218ddf9667bf7f370bf7fdb2cb15fdd0aa49"
integrity sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=

fast-equals@^1.6.1:
version "1.6.2"
resolved "https://registry.yarnpkg.com/fast-equals/-/fast-equals-1.6.2.tgz#f1762bde0d571b5e9d4e1c4ae0599792f6a6df5f"
integrity sha512-6FiKwHkrHIqdvo9I92yzCR/zuWE6iy5ldcOszStPbmo7Zzj3OoVeng++GE//JqO4i6JQ4vH/BVAfCmUCki+C3g==

fast-glob@^2.2.6:
version "2.2.6"
resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-2.2.6.tgz#a5d5b697ec8deda468d85a74035290a025a95295"
Expand Down Expand Up @@ -6672,6 +6677,13 @@ run-queue@^1.0.0, run-queue@^1.0.3:
dependencies:
aproba "^1.1.1"

rxjs-marbles@^5.0.0:
version "5.0.0"
resolved "https://registry.yarnpkg.com/rxjs-marbles/-/rxjs-marbles-5.0.0.tgz#b46b4d6ed8ff62da9b5da6df1bcb423df56c72f4"
integrity sha512-Twr69tKSxC4ObE/afKJtSPuw+hVE5Paul8KlHhVsnOpqnSHiOd9Ff94RUx+fsCXYsnEILrf4qLsXpHlYzG4a9Q==
dependencies:
fast-equals "^1.6.1"

rxjs@^6.3.3:
version "6.3.3"
resolved "https://registry.yarnpkg.com/rxjs/-/rxjs-6.3.3.tgz#3c6a7fa420e844a81390fb1158a9ec614f4bad55"
Expand Down

0 comments on commit 63fb590

Please sign in to comment.