microsoft / TypeScript

TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
https://www.typescriptlang.org
Apache License 2.0
101.27k stars 12.52k forks source link

Combine few classes in one with decorators #8876

Closed SET001 closed 8 years ago

SET001 commented 8 years ago

Recently I was playing with TypeScript decorators and ended up with interesting pattern. It is possible to extend some basic class with any number of other classes. The idea is to extend decorated class prototype with prototypes of classes from decorator. This is somehow different from traditional class inheritance. It is more like adding plugins:

So here is the example decorator which extends some class with plugins:

export function Plugins(plugins: any[]): any{
  return function(target: any){
    var layer = function(){};
    layer.prototype = target.prototype;
    for (var plugin of plugins){
      _.extend(layer.prototype, plugin.prototype);
    }
    return target;
  }
}

Now let's say we have class that handles connection. Something like this.

export class SocketIOClientConnection extends ConnectionLayer{
    constructor(public socket?: SocketIO.Socket){}

    send(message: string){
        this.socket.emit(message);
    }

    broadcast(message: string){
        this.socket.emit(message);
    }
    disconnect(){}
}

and imagine that all socket events are somehow binded to this class methods which begin with on. Then we can decorate this connection class with some plugins which would add handlers of some sort. We can have auth, chat, streamer and as many plugins we ever want.

export class AuthConnection extends ConnectionLayer{
    onLogIn(login?: string, password?: string){
        this.socket.send('loggedOn');   
    }
    onLogOut(){
        this.socket.send('loggedOut');
    }
    onRegister(){}
}

we can decorate connection method it this way

@Plugins([AuthConnection])
export class SocketIOClientConnection extends ConnectionLayer{

and now it will be able to handle login requests... The goals of this approach is that auth implementation know nothing about how exactly connection handled. We can have socketIO or webRTC or whatever class implementing some interface and decorated with this auth plugins.

Now few questions:

What do you think about this approach? Is it ok to use decorators in this way? Maybe this pattern already exist and have some name? any readings on this? What pitfalls this approach have? (for example, plugins can not have methods with same name and so on)

kitsonk commented 8 years ago

This isn't always the best forum for general TypeScript discussion. StackOverflow, gitter or #typescript on IRC are usually better.

Any mutations to make to the prototype are not reflected in the classes types. There are a few discussions about programmatically modifying the types (see #4490), but nothing yet delivered, although it will likely be delivered via ambient decorators in TS 2.1 (see #2900).

Angular 2 makes heavy use of decorators in creating its components, though, as mentioned, since changes to the prototype are not reflected in the type information about the class, it is generally limited to assigning/mutating values of the prototype.

Decorators are not a "TypeScript" thing. They are essentially an implementation of the Stage 1 proposal of ECMAScript Decorators.