Skip to content

Instantly share code, notes, and snippets.

@crobinson42
Forked from sidola/pubsub.ts
Last active January 23, 2022 20:02
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save crobinson42/1153e6d786abb526c6adf775aba60887 to your computer and use it in GitHub Desktop.
Save crobinson42/1153e6d786abb526c6adf775aba60887 to your computer and use it in GitHub Desktop.
Basic typesafe pub-sub implementation in Typescript
/**
* Defines the function type of the publish function.
*
* Extracts the keys from `E` as valid event types, and the matching
* property as the payload.
*/
type PubTypeFn<E> = <Key extends string & keyof E>(
event: Key,
fn: (message: E[Key]) => void
) => void
/**
* Defines the function type for the subscribe function.
*
* Extracts the keys from `E` as valid event types, and the matching
* property as the payload to the callback function.
*/
type SubTypeFn<E> = <Key extends string & keyof E>(
event: Key,
fn: (message: E[Key]) => void
) => void
/**
* Defines the function type for the subscription callback. Ensures
* the message payload is a valid property of the event being used.
*/
type MessageFn<E> = <Key extends string & keyof E>(message: E[Key]) => void
/**
* Tie everything together.
*/
type PubSubType<E> = {
publish: PubTypeFn<E>,
subscribe: SubTypeFn<E>
unsubscribe: SubTypeFn<E>
}
/**
* Creates a new PubSub instance, the `E` type parameter should be a
* type enumerating all the available events and their payloads.
*
* @example
* type Events = {
* warn: { message: string },
* error: { message: string }
* }
*
* const pubSub = PubSub<Events>()
* pubSub.publish('warn', { message: "Something bad happened!" })
*/
export function PubSub<E>(): PubSubType<E> {
const handlers: { [key: string]: (MessageFn<any>)[] } = {}
return {
publish: (event, msg) => {
handlers[event].forEach(h => h(msg))
},
subscribe: (event, callback) => {
const list = handlers[event] ?? []
list.push(callback)
handlers[event] = list
},
unsubscribe: (event, callback) => {
let list = handlers[event] ?? []
list = list.filter(h => h !== callback)
handlers[event] = list
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment