UNPKG

foibles

Version:

Composition and mixins and TypeScript classes

73 lines 2.24 kB
// Symbol used to mark if a certain mixin has been applied const application = Symbol('decorator:application'); /** * Check if the given prototype has the given mixin applied to itself. * * @param object * @param mixin */ function has(object, mixin) { while (object != null) { if (object.hasOwnProperty(application) && object[application] === mixin) { return true; } object = Object.getPrototypeOf(object); } } /** * Turn a function into a fully featured mixin. The mixin function should be * a function which takes a single argument which is the class to extend and * the function must return an extended class. * * ```javascript * const ExampleMixin = toMixin(base => class extends base { * ... * }); * ``` * * @param func */ export function toMixin(func) { /* * Define a function that checks if the mixin has already been applied * to the prototype chain. This allows mixins to use other mixins as needed * without them being applied twice. */ const mixinOnce = function (base) { if (has(base.prototype, func)) return base; const result = func(base); result.prototype[application] = func; return result; }; /* * Define a custom hasInstance symbol so that instanceof can be used if * the environment supports it. */ if (Symbol.hasInstance) { if (func.hasOwnProperty(Symbol.hasInstance)) { /* * Mixin has its own hasInstance, let the outer function delegate * to it. */ Object.defineProperty(mixinOnce, Symbol.hasInstance, { value: function mixinHasInstance(other) { return func[Symbol.hasInstance](other); } }); } else { /* * The mixin function does not have a custom hasInstance, use our * own. */ Object.defineProperty(mixinOnce, Symbol.hasInstance, { value: function mixinHasInstance(other) { return has(other, func); } }); } } return mixinOnce; } //# sourceMappingURL=mixin.js.map