0

I would like to create an instance of a class without invoking its constructor.

For example,

class Test {
    private greeting: string = "Hello";

    constructor() { 
        console.log("this should not happen"); 
    }

    foo() { 
        console.log(this.greeting + " world!"); 
    }
}

magic({greeting: "Hey"}, Test) instanceof Test // true

For some context, I am working on an ORM. I need this to create JavaScript objects while bypassing the constructor. This is required to create plain-old-objects without the need for factories or parameter-less constructors.

9
  • 5
    Smells heavily of an XY problem. Can you explain why you want to do that? I suspect your approach is wrong. Commented Jan 27, 2021 at 17:08
  • It's constructor, not construct. You could just pass a Boolean argument to it, defaulted to false constructor(doFrouFrou = false) { if (doFrouFrou) { console.log('this should happen only if doFrouFrou is true'); } } Then var test = new Test(); would not log anything... But it looks like you want more than that, because you want to set private variables of this new instance without needing to have an accessor for it. Now that's crazy talk. :) Commented Jan 27, 2021 at 17:32
  • 1
    @HereticMonkey well, you can still access private variables in TS. You just have to trick the compiler. However, if you need to do that, then most likely the class is wrong to begin with. Or you're using it wrong. Commented Jan 27, 2021 at 17:39
  • The question wasn't flagged with TypeScript, but it has the wrong syntax for ECMAScript private variables, but the code seemed like pseudo code anyway... I totally agree about the XY problem. Commented Jan 27, 2021 at 17:41
  • "This is required to create plain-old-objects" but at the same time you want them to be an instance of a class? They aren't plain in that case. The explanation is contradictory. Commented Jun 21, 2021 at 9:09

2 Answers 2

1

The "magic" you are looking for is probably the Object.create function:

let t = Object.create(Test.prototype, {
    greeting: {
        value: "Hey",
        writable: true
    },
});

By the way, as pointed out in the comments, I do not think you should skip the constructor. If you really need to, at least tell us the real problem you have.

Sign up to request clarification or add additional context in comments.

1 Comment

OP made the reason clear already: writing an ORM. It's a problem I have also run into, where the user is allowed to extend a base model class and provide their own constructor for convenience. When the ORM retrieves and denormalizes objects from the db, this constructor should not be run, as it may throw, and the signature is not known by the ORM in any case.
0

Object.setPrototypeOf will do most of the work.

const rawObject = {greeting: 'Hey'};
const testInstance = Object.setPrototypeOf(rawObject, Test.prototype);

However, note that this approach will override any getter/setter methods. Use this to provide the underlying value instead.

For example,

class Test {
    _greeting;
    
    get greeting() {
        return this._greeting;
    }
}

const a = Object.setPrototypeOf({greeting: 'Hey'}, Test.prototype);
console.log(a.greeting); // Hey
a._greeting = 'Hello';
console.log(a.greeting); // Hey

const b = Object.setPrototypeOf({_greeting: 'Hey'}, Test.prototype);
console.log(b.greeting); // Hey
b._greeting = 'Hello';
console.log(b.greeting); // Hello

3 Comments

Objects with getters are also not plain... Also, this is not a very scalable approach. You need to know internal logic of the object you create in order to create it. That code belongs as part of the object itself - either as a constructor or a factory method. Otherwise, your code is tightly coupled and thus brittle to change.
That's what I am asking, how to create an object without any knowledge of its creation logic (constructor). I am not asking whether it's a good idea.
Then the generic answer is "no". Because you cannot know whether it has getters or setters or what logic they use. Not easily. Only very simple objects can be created and even then you need to know what the object definition is, in order to create them. If you have no control over the class (thus you cannot add a factory method), the correct solution is to create your own separate factory that maintains a list of creators. Yet, your question also restricts that from being an option without adequate explanation.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.