Skip to content

Instantly share code, notes, and snippets.

@mindplay-dk
Last active October 26, 2015 10:07
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 mindplay-dk/aac7f7673f492cf4f24d to your computer and use it in GitHub Desktop.
Save mindplay-dk/aac7f7673f492cf4f24d to your computer and use it in GitHub Desktop.
Type-safe event hooks and boxed values (aka "getter-setters") in Typescript
/// This interface defines an event listener
interface IListener<Event> {
(event: Event): void
}
/// This interface represents an event hook
interface IHook<Event> {
/// Attach a handler to this hookable
(handler: IListener<Event>): void
/// Send an event to all listeners
(event: Event): void
or<Other>(other: IHook<Other>) : IHook<Event|Other>
}
/// This interface represents a hookable boxed value
interface IBox<T> extends IHook<T> {
/// Retrieve the value
() : T
}
/// Create an event hook for a specific type of message
function hook<Event>(getter? : { (): Event }): IHook<Event> {
var _handlers: Array<Function> = []
var _busy = false
var _getter = getter; // || function () { return null; };
function invoke(message)
function invoke(event: Event)
function invoke() {
if (arguments.length === 0) {
return _getter();
} else if (arguments[0] instanceof Function) {
_handlers.push(arguments[0])
} else if (!_busy) {
_busy = true
for (var i = 0; i < _handlers.length; i++) {
_handlers[i].apply(this, arguments)
}
_busy = false
}
}
invoke["or"] = function <Other> (other: IHook<Other>) : IHook<Event|Other> {
return <IHook<Event>> function (event: Event|Other) {
invoke(<Event> event)
other(<Other> event)
}
}
return <IHook<Event>> <any> invoke
}
/// Create a hookable boxed value (optionally with an initial value)
function box<T>(value?: T): IBox<T> {
var _value: T = value
var _hook = hook(() => _value)
_hook((value: T) => _value = value)
return <IBox<T>> _hook;
}
// EXAMPLE:
class User {
first_name = box("Foo")
last_name = box("Bar")
}
class Model {
onLogin = hook<{user: User}>()
}
var model = new Model()
model.onLogin(e => console.log("Logged in: " + e.user.first_name()))
var user = new User()
user.first_name.or(user.last_name)((value) => console.log("updated: ", value))
user.first_name("Rasmus")
user.last_name("Schultz")
model.onLogin({user})
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment