-
-
Save revskill10/8c8d1c7603bacb0a0a9f1dd549e87c09 to your computer and use it in GitHub Desktop.
Basic typesafe pub-sub implementation in Typescript
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* ------------------------------------------ | |
Alternative impl. as a class can be found here: https://gist.github.com/sidola/eaf987d8c4c7e8445b61dc07c33a842f | |
Has a way smaller footprint and less typescript magic to grasp. | |
------------------------------------------ */ | |
/** | |
* 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, | |
message: E[Key] | |
) => 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. | |
* | |
* Returns the given callback. | |
*/ | |
type SubTypeFn<E> = <Key extends string & keyof E>( | |
event: Key, | |
fn: (message: E[Key]) => void | |
) => (message: E[Key]) => void | |
/** | |
* Defines the function type for the unsubscribe function. | |
* | |
* Extracts the keys from `E` as valid event types, and the matching | |
* property as the payload to the callback function. | |
*/ | |
type UnsubTypeFn<E> = <Key extends string & keyof E>( | |
event: Key, | |
fn: (message: E[Key]) => void | |
) => void | |
/** | |
* Tie everything together. | |
*/ | |
type PubSubType<E> = { | |
publish: PubTypeFn<E> | |
subscribe: SubTypeFn<E> | |
unsubscribe: UnsubTypeFn<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>() | |
* const subHandle = pubSub.subscribe('warn', (message) => { | |
* console.warn(message) | |
* }) | |
* | |
* pubSub.publish('warn', { message: "Something bad happened!" }) | |
* pubSub.unsubscribe('warn', subHandle) | |
*/ | |
export function PubSub<E>(): PubSubType<E> { | |
// This any[] is our list of handlers functions. We don't have the | |
// necessary type information in here which is why it's any-typed. | |
const handlers: { [key: string]: any[] } = {} | |
return { | |
publish: (event, msg) => { | |
handlers[event].forEach(h => h(msg)) | |
}, | |
subscribe: (event, callback) => { | |
const list = handlers[event] ?? [] | |
list.push(callback) | |
handlers[event] = list | |
return callback | |
}, | |
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