I'm trying to understand how class decorators work in Typescript when we wish to replace the constructor. I've seen this demo:
const log = <T>(originalConstructor: new(...args: any[]) => T) => {
function newConstructor(... args) {
console.log("Arguments: ", args.join(", "));
new originalConstructor(args);
}
newConstructor.prototype = originalConstructor.prototype;
return newConstructor;
}
@log
class Pet {
constructor(name: string, age: number) {}
}
new Pet("Azor", 12);
//Arguments: Azor, 12
Everything is understood but this line:
newConstructor.prototype = originalConstructor.prototype;
Why do we do that?
I'm trying to understand how class decorators work in Typescript when we wish to replace the constructor. I've seen this demo:
const log = <T>(originalConstructor: new(...args: any[]) => T) => {
function newConstructor(... args) {
console.log("Arguments: ", args.join(", "));
new originalConstructor(args);
}
newConstructor.prototype = originalConstructor.prototype;
return newConstructor;
}
@log
class Pet {
constructor(name: string, age: number) {}
}
new Pet("Azor", 12);
//Arguments: Azor, 12
Everything is understood but this line:
newConstructor.prototype = originalConstructor.prototype;
Why do we do that?
Share Improve this question asked Jun 13, 2017 at 10:44 RiskXRiskX 5916 silver badges22 bronze badges 2-
Let's start with the fact that your code doesn't really do what you think it does. It doesn't work. Change the ctor to
constructor(public name: string, public age: number)
and then try to access the instance members (name
andage
) and you'll getundefined
. Check this question for the right way of doing it: stackoverflow./questions/39198811/… – Nitzan Tomer Commented Jun 13, 2017 at 11:03 - Hi, This code is from the internet, I don't care if it works I just need to know why we need this line because I've seen it in more examples – RiskX Commented Jun 13, 2017 at 11:27
1 Answer
Reset to default 3The classes like:
class Pet {
constructor(name: string, age: number) {}
dosomething() {
console.log("Something...");
}
}
Are piled into functions when targeting ES5:
var Pet = (function () {
function Pet(name, age) {
}
Pet.prototype.dosomething = function () {
console.log("Something...");
};
return Pet;
}());
As you can seem when we use functions to define classes. The methods are added to the function's prototype.
This means that if you are going to create a new constructor (new function) you need to copy all the methods (the prototype) from the old object:
function logClass(target: any) {
// save a reference to the original constructor
const original = target;
// a utility function to generate instances of a class
function construct(constructor: any, args: any[]) {
const c: any = function () {
return constructor.apply(this, args);
};
c.prototype = constructor.prototype;
return new c();
}
// the new constructor behaviour
const newConstructor: any = function (...args: any[]) {
console.log("New: " + original.name);
return construct(original, args);
};
// copy prototype so intanceof operator still works
newConstructor.prototype = original.prototype;
// return new constructor (will override original)
return newConstructor;
}
You can learn more at "Decorators & metadata reflection in TypeScript: From Novice to Expert (Part I)"
Update
Please refer to https://github./remojansen/LearningTypeScript/tree/master/chapters/chapter_08 for a more recent version.