Giter Club home page Giter Club logo

Comments (3)

DanielRosenwasser avatar DanielRosenwasser commented on May 17, 2024

This could probably use union types, and potentially local types.

from typescript-handbook.

DustinWehr avatar DustinWehr commented on May 17, 2024

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.

  1. 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 of smartObject.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.
  2. 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.

 avatar commented on May 17, 2024

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)

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo 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.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.