Last active
October 26, 2015 10:07
-
-
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 file contains 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
/// 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