Comments (3)
This could probably use union types, and potentially local types.
from typescript-handbook.
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.
I'll give a short summary, then some items of differences between the new pattern and the Handbook's, and then the example from the Handbook rewritten in terms of the new pattern. I have no opinion about naming conventions, so please do suggest alternatives.
For the summary I'll use the example as a reference. The new pattern produces a namespace ActivatableMixin with three visible members:
-An interface, ActivatableInterface
-A function usedBy
, which tests if an object's class uses the mixin. This is the main improvement over the Handbook pattern.
-A function mixInto
, such that ActivatableMixin.mixInto(C)
does everything that the Handbook's applyMixins(C, [Activatable])
does, and additionally stores the class C
, so we can later use (x instanceof C)
in ActivatableMixin.usedBy
.
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.
- Added an option to exclude "constructor" from the mixed-in property names. In the code below (see makeMixinApplicator) it defaults to true. When it's excluded, you have
smartObject.constructor === SmartObject
instead ofsmartObject.constructor === <constructor of last-supplied mixin>
, which I think is less surprising, at least for someone like me who didn't know the JS prototype system well when first learning TS. - The implementation of the mixin is hidden. This is so that a new TS user doesn't mistakenly think they can use instanceof to check if an object implements a mixin. It's an easy mistake to make since
smartObject instanceof Activatable
compiles fine.
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;
}
}
from typescript-handbook.
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.
from typescript-handbook.
Related Issues (20)
- `export =` also works with `import * as` HOT 1
- Typos in Enums and Type Inference
- awesome-typescript-loader is no longer maintained.
- Declaration example does not match documentation requirements HOT 1
- Documented applyMixins doesn't compile since TypeScript 2.7 HOT 1
- Samples code in "Metadata" section of "Decorators" page is wrong
- Exhaustiveness checking current state
- typeof operator isn't documented HOT 6
- Misstatement in definition of `Partial<T>` HOT 1
- Typo on "Unions and Intersections" page HOT 2
- Please expand Type Checking JavaScript Files into mutiple sections HOT 1
- Broken link in the Compiler Options page HOT 1
- create project fail HOT 1
- in operator clarification
- Outdated information about circular references of type aliases
- Add an entry about "typesVersions" to the handbook HOT 1
- Typos in "Advanced Types"
- `this` is a keyword, not a variable
- Incorrect example on "Compiler Options" HOT 1
- Incorrect tree node definition in pages/Advanced Types.md
Recommend Projects
-
React
A declarative, efficient, and flexible JavaScript library for building user interfaces.
-
Vue.js
🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
-
Typescript
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
-
TensorFlow
An Open Source Machine Learning Framework for Everyone
-
Django
The Web framework for perfectionists with deadlines.
-
Laravel
A PHP framework for web artisans
-
D3
Bring data to life with SVG, Canvas and HTML. 📊📈🎉
-
Recommend Topics
-
javascript
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
-
web
Some thing interesting about web. New door for the world.
-
server
A server is a program made to process requests and deliver data to clients.
-
Machine learning
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
-
Visualization
Some thing interesting about visualization, use data art
-
Game
Some thing interesting about game, make everyone happy.
Recommend Org
-
Facebook
We are working to build community through open source technology. NB: members must have two-factor auth.
-
Microsoft
Open source projects and samples from Microsoft.
-
Google
Google ❤️ Open Source for everyone.
-
Alibaba
Alibaba Open Source for everyone
-
D3
Data-Driven Documents codes.
-
Tencent
China tencent open source team.
from typescript-handbook.