-
Notifications
You must be signed in to change notification settings - Fork 1.1k
Review Mixins for language changes #15
Comments
This could probably use union types, and potentially local types. |
I took some time (too much) to refine the Mixin pattern I've been using, with the intention of offering to write a new version of http://www.typescriptlang.org/Handbook#mixins if you guys like it. I think it's a good use of user-defined type guard functions. For the summary I'll use the example as a reference. The new pattern produces a namespace ActivatableMixin with three visible members: In addition to the usedBy function, I'm suggesting two small alterations to prevent some surprising behavior of the current Handbook pattern that bit me.
namespace DisposableMixin {
var classesUsingThis : Function[] = [];
export interface DisposableInterface {
isDisposed: boolean;
dispose() : void;
}
class DisposableImplementation implements DisposableInterface {
isDisposed:boolean;
dispose():void {
this.isDisposed = true;
}
}
export var mixInto = makeMixinApplicator(DisposableImplementation, classesUsingThis);
export var usedBy = makeMixinInstanceChecker<DisposableInterface>(classesUsingThis);
}
namespace ActivatableMixin {
var classesUsingThis : Function[] = [];
export interface ActivatableInterface {
isActive: boolean
activate() : void
deactivate() : void
}
class ActivatableImplementation implements ActivatableInterface {
isActive: boolean;
activate() {
this.isActive = true;
}
deactivate() {
this.isActive = false;
}
}
export var mixInto = makeMixinApplicator(ActivatableImplementation, classesUsingThis);
export var isActivatable = makeMixinInstanceChecker<ActivatableInterface>(classesUsingThis);
}
import DisposableInterface = DisposableMixin.DisposableInterface;
import ActivatableInterface = ActivatableMixin.ActivatableInterface;
class SmartObject implements DisposableInterface, ActivatableInterface {
constructor() {
setInterval(() => console.log("activated: " + this.isActive + " | disposed: " + this.isDisposed), 500);
}
interact() {
this.activate();
}
// Disposable
isDisposed: boolean = false;
dispose: () => void;
// Activatable
isActive: boolean = false;
activate: () => void;
deactivate: () => void;
}
DisposableMixin.mixInto(SmartObject);
ActivatableMixin.mixInto(SmartObject);
var smartObj = new SmartObject();
setTimeout(() => smartObj.interact(), 1000);
////////////////////////////////////////
// In your runtime library somewhere
////////////////////////////////////////
function makeMixinApplicator(mixinImplementation:any, classesUsingMixin:any[], exclude_constructor=true) : (c:any) => void {
return (c:any) => {
classesUsingMixin.push(c);
Object.getOwnPropertyNames(mixinImplementation.prototype).forEach(name => {
if(!exclude_constructor || name !== "constructor") {
(<any>c.prototype)[name] = (<any>mixinImplementation.prototype)[name];
}
})
};
}
function makeMixinInstanceChecker<T>(classesUsingMixin:Function[]) : ( (x:any) => x is T ) {
return (x:any) : x is T => {
for(let i=0; i<classesUsingMixin.length; i++) {
if(x instanceof classesUsingMixin[i])
return true;
}
return false;
}
} |
We should include documentation like https://blog.mariusschulz.com/2017/05/26/typescript-2-2-mixin-classes -- our current documentation makes no mention of being able to do that. |
Update this file so that it is up-to-date with regard to new language features, especially around union types and ES6 features
The text was updated successfully, but these errors were encountered: