Comparing version 0.4.0 to 0.5.0
@@ -17,3 +17,3 @@ import { EventEmitter2 as EventEmitter } from "eventemitter2"; | ||
}; | ||
export declare function createEventDefinition<P>(options?: EventDefinitionOptions<P> | TestPredicateFn<P>): <T extends string>(type: T) => { | ||
export declare function createEventDefinition<P = void>(options?: EventDefinitionOptions<P> | TestPredicateFn<P>): <T extends string>(type: T) => { | ||
(payload: P): { | ||
@@ -20,0 +20,0 @@ type: T; |
@@ -29,5 +29,5 @@ "use strict"; | ||
return function (type) { | ||
var eventCreator = function (payload) { | ||
function eventCreator(payload) { | ||
// Allow runtime payload checking for plain JavaScript usage | ||
if (options) { | ||
if (options && payload) { | ||
var testFn = typeof options === "function" ? options : options.test; | ||
@@ -42,3 +42,3 @@ if (testFn && !testFn(payload)) { | ||
}; | ||
}; | ||
} | ||
eventCreator.eventType = type; | ||
@@ -45,0 +45,0 @@ eventCreator.toString = function () { return type; }; // allow String coercion to deliver the eventType |
@@ -44,2 +44,24 @@ "use strict"; | ||
}); | ||
describe("createEmptyEventDefinition", function () { | ||
it("should work with createEmptyEventDefinition and an empty payload", function () { | ||
// mock subscription | ||
var handleSubscription = jest.fn(); | ||
var myEventCreator = index_1.createEventDefinition()("myevent"); | ||
// create a bus | ||
var bus = new index_1.EventBus(); | ||
bus.subscribe(myEventCreator, handleSubscription); | ||
// create n event | ||
var event = myEventCreator(); | ||
// Call it once | ||
bus.publish(event); | ||
expect(handleSubscription.mock.calls).toEqual([ | ||
[ | ||
{ | ||
type: "myevent", | ||
payload: undefined | ||
} | ||
] | ||
]); | ||
}); | ||
}); | ||
it("should show deprecation warning when using defineEvent", function () { | ||
@@ -46,0 +68,0 @@ mockWarn.mockReset(); |
{ | ||
"name": "ts-bus", | ||
"version": "0.4.0", | ||
"version": "0.5.0", | ||
"main": "index.js", | ||
@@ -20,2 +20,3 @@ "license": "MIT", | ||
"devDependencies": { | ||
"@testing-library/react-hooks": "^1.1.0", | ||
"@types/jest": "^24.0.15", | ||
@@ -26,2 +27,4 @@ "@types/node": "^12.6.8", | ||
"jest": "^24.8.0", | ||
"react": "^16.8.6", | ||
"react-test-renderer": "^16.8.6", | ||
"ts-jest": "^24.0.2", | ||
@@ -28,0 +31,0 @@ "typescript": "^3.5.1" |
128
README.md
@@ -107,3 +107,3 @@ <p align="center"> | ||
Notice we need to call the curried function to create the event creator this is because it is [the only way we can allow effective discriminated unions](https://github.com/ryardley/ts-bus/issues/9). | ||
Notice `createEventDefinition()` will often be called with out a runtime check argument and it returns a function that accepts the event type as an argument. Whilst possibly a tiny bit awkward, this is done because it is [the only way we can allow effective discriminated unions](https://github.com/ryardley/ts-bus/issues/9). See [switching on events](#switching-on-events-and-discriminated-unions). | ||
@@ -122,34 +122,78 @@ ### Runtime payload checking | ||
### Subscription | ||
### Subscribing | ||
Let's subscribe to our events | ||
```ts | ||
// main.ts | ||
import { taskLabelUpdated, taskCreated } from "./event"; | ||
import { bus } from "./bus"; | ||
// You can subscribe using the event factory function should you wish | ||
const unsubscribe = bus.subscribe(taskLabelUpdated, event => { | ||
const { id, label } = event.payload; // Event typing should be available | ||
// You can subscribe using the event creator function | ||
bus.subscribe(taskLabelUpdated, event => { | ||
const { id, label } = event.payload; // Event is typed | ||
doSomethingWithLabelAndId({ id, label }); | ||
}); | ||
``` | ||
// Unsubscribe to taskLabelUpdated after 20 seconds | ||
setTimeout(unsubscribe, 20 * 1000); | ||
### Unsubscribing | ||
// Or you can use plain old type strings | ||
To unsubscribe from an event use the returned unsubscribe function. | ||
```ts | ||
const unsubscribe = bus.subscribe(taskLabelUpdated, event => { | ||
// ... | ||
}); | ||
unsubscribe(); // removes event subscription | ||
``` | ||
### Subscribing with a type string | ||
You can use the event type to subscribe. | ||
```ts | ||
bus.subscribe("task.created", event => { | ||
const { listId, id, value } = event.payload; | ||
appendTaskToList(listId, { id, value }); | ||
// ... | ||
}); | ||
``` | ||
// Alternatively you can use a predicate function | ||
const taskCreated = event => event.type === "task.created"; | ||
bus.subscribe(taskCreated, event => { | ||
const { listId, id, value } = event.payload; | ||
appendTaskToList(listId, { id, value }); | ||
Or you can use [wildcards](#wildcard-syntax): | ||
```ts | ||
bus.subscribe("task.**", event => { | ||
// ... | ||
}); | ||
``` | ||
### Subscribing with a predicate function | ||
You can also subscribe using a predicate function to filter events. | ||
```ts | ||
// A predicate | ||
function isSpecialEvent(event) { | ||
return event.payload && event.payload.special; | ||
} | ||
bus.subscribe(isSpecialEvent, event => { | ||
// ... | ||
}); | ||
``` | ||
You may find [pdsl](https://github.com/ryardley/pdsl) a good fit for creating predicates. | ||
### Subscription syntax | ||
As you can see above you can subscribe to events by using the `subscribe` method of the bus. | ||
```ts | ||
const unsubscriber = bus.subscribe(<string|eventCreator|predicate>, handler); | ||
``` | ||
This subscription function can accept a few different options for the first argument: | ||
* A `string` that is the specific event type or a wildcard selector eg. `mything.**`. | ||
* An `eventCreator` function returned from `createEventDefinition<PayloadType>()("myEvent")` | ||
* A `predicate` function that will only subscribe to events that match the predicate. Note the predicate function matches the entire `event` object not just the payload. Eg. `{type:'foo', payload:'foo'}` | ||
The returned `unsubscribe()` method will unsubscribe the specific event from the bus. | ||
### Publishing events | ||
@@ -198,13 +242,13 @@ | ||
// This is a shorthand utility that creates predicate functions based on a given object shape. | ||
// This is a shorthand utility that creates predicate functions to match based on a given object shape. | ||
// For more details see https://github.com/ryardley/pdsl | ||
const predicateFn = p`{ | ||
type:${/^shared\./}, | ||
meta: { | ||
remote: !true | ||
} | ||
const isSharedAndNotRemoteFn = p`{ | ||
type: ${/^shared\./}, | ||
meta: { | ||
remote: !true | ||
} | ||
}`; | ||
// Prevent sending a event-sync if the event was remote | ||
bus.subscribe(predicateFn, event => { | ||
bus.subscribe(isSharedAndNotRemoteFn, event => { | ||
socket.emit("event-sync", event); | ||
@@ -214,2 +258,34 @@ }); | ||
### Switching on Events and Discriminated Unions | ||
```ts | ||
// This function creates foo events | ||
const fooCreator = createEventDefinition<{ | ||
foo:string | ||
}>()("shared.foo"); | ||
// This function creates bar events | ||
const barCreator = createEventDefinition<{ | ||
bar:string | ||
}>()("shared.bar"); | ||
// Create a union type to represent your app events | ||
type AppEvent = ReturnType<typeof fooCreator> | ReturnType<typeof barCreator>; | ||
bus.subscribe("shared.**", (event:AppEvent) => { | ||
switch(event.type){ | ||
case String(fooCreator): | ||
// compiler is happy about payload having a foo property | ||
alert(event.payload.foo.toLowerCase()); | ||
break; | ||
case String(barCreator): | ||
// compiler is happy about payload having a bar property | ||
alert(event.payload.bar.toLowerCase()); | ||
break; | ||
default: | ||
} | ||
}); | ||
``` | ||
### Wildcard syntax | ||
@@ -226,3 +302,3 @@ | ||
This is inherited directly from EventEmitter2 which ts-bus currently uses under the hood. I would like to investigate a stronger pattern matching syntax in the future that can take account of payload and event metadata. Submit an issue if you have ideas for syntax etc. | ||
This is inherited directly from EventEmitter2 which ts-bus currently uses under the hood. | ||
@@ -229,0 +305,0 @@ ## React extensions |
import { EventBus } from "./EventBus"; | ||
import { BusEvent } from "./types"; | ||
declare type DispatchFn<E> = (a: E) => void; | ||
export declare function _defaultSubscriber<E extends BusEvent>(dispatch: DispatchFn<E>, bus: EventBus): () => import("eventemitter2").EventEmitter2; | ||
export declare function useBusReducer<E extends BusEvent = BusEvent, T = any>(initState: T, reducer: (s: T, a: E) => T, subscriber?: (dispatch: DispatchFn<E>, bus: EventBus) => void): T; | ||
export {}; |
@@ -5,7 +5,8 @@ "use strict"; | ||
var react_2 = require("./react"); | ||
function defaultSubscriber(dispatch, bus) { | ||
bus.subscribe("**", dispatch); | ||
function _defaultSubscriber(dispatch, bus) { | ||
return bus.subscribe("**", dispatch); | ||
} | ||
exports._defaultSubscriber = _defaultSubscriber; | ||
function useBusReducer(initState, reducer, subscriber) { | ||
if (subscriber === void 0) { subscriber = defaultSubscriber; } | ||
if (subscriber === void 0) { subscriber = _defaultSubscriber; } | ||
// Pull the bus from context | ||
@@ -12,0 +13,0 @@ var bus = react_2.useBus(); |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
273491
30
546
384
10