Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to properly wrap constructors with decorators in TypeScript

Tags:

The process of wrapping a class with a decorator causes superclasses to be unable to access that classes' properties. Why?

I have some code that:

  1. Creates a decorator which replaces the constructor of a class with a new constructor that should do the exact same thing.
  2. Creates a base class with a property.
  3. Wraps the base class with the wrapping decorator.
  4. Creates a class that extends the base class.
  5. Tries to access the property on the extended class. This is the part that fails.

Here is the code:

function wrap(target: any) {   // the new constructor   var f: any = function (...args) {       return new target();   }    f.prototype = target.prototype;   return f; }  @wrap class Base {     prop: number = 5; }  class Extended extends Base {     constructor() {         super()     } }  var a = new Extended() console.log(new Extended().prop) // I'm expecting 5 here, but I get undefined. 

I'm sure this is some nuance of either prototypes in general or the specific way that TypeScript handles them that I do not grasp.

like image 802
thedayturns Avatar asked Dec 22 '15 08:12

thedayturns


People also ask

Can I use decorators in TypeScript?

Decorators provide a way to add both annotations and a meta-programming syntax for class declarations and members. Decorators are a stage 2 proposal for JavaScript and are available as an experimental feature of TypeScript. NOTE Decorators are an experimental feature that may change in future releases.

Are decorators still experimental in TypeScript?

TypeScript decorators are cool, but still experimental and not standardised.

What is target in decorator TypeScript?

The first parameter is commonly called target . The sealed decorator will be used only on class declarations, so your function will receive a single parameter, the target , which will be of type Function . This will be the constructor of the class that the decorator was applied to.

How many decorators can be applied to a declaration?

It's possible to use as many decorators on the same piece of code as you desire, and they'll be applied in the order that you declare them. This defines a class and applies three decorators — two to the class itself, and one to a property of the class: @log could log all access to the class.


2 Answers

This is the more modern approach using the latest TS (3.2.4). The below also uses the decorator factory pattern so you can pass in attributes:

function DecoratorName(attr: any) {   return function _DecoratorName<T extends {new(...args: any[]): {}}>(constr: T){     return class extends constr {       constructor(...args: any[]) {         super(...args)         console.log('Did something after the original constructor!')         console.log('Here is my attribute!', attr.attrName)       }     }   } } 

See here for more info: https://www.typescriptlang.org/docs/handbook/decorators.html#class-decorators

like image 64
etech Avatar answered Oct 21 '22 05:10

etech


This code works for me:

function logClass(target: any) {   // save a reference to the original constructor   var original = target;    // the new constructor behaviour   var f : any = function (...args) {     console.log("New: " + original.name);      //return  original.apply(this, args);     return new original(...args); // according the comments   }    // copy prototype so intanceof operator still works   f.prototype = original.prototype;    // return new constructor (will override original)   return f; }  @logClass class Base {     prop: number = 5; }  class Extended extends Base {     constructor() {         super()     } }  var b = new Base() console.log(b.prop)  var a = new Extended() console.log(a.prop) 
like image 24
TSV Avatar answered Oct 21 '22 04:10

TSV