4

I have used an implementation as given below in JavaScript.

class Base {
    installGetters() {
        Object.defineProperty(this, 'add', {
            get() {
                return 5;
            }
        });
    }
}

class New extends Base {
    constructor() {
        super();
        this.installGetters();
    }

    someAddition() {
        return 10 + this.add;
    }
}

I have defined the getter property add in the function of the parent class - Base and used that property in child class New after calling the installGetters() function in the child class constructor. This works for JavaScript, but this.add is throwing an error in case of Typescript. Any help would be much appreciated.

My main motivation for doing this is that I want to pass an object to installGetters() so that it can generate multiple getters with the object keys being the getter names and the values being returned from the corresponding getter functions.

This is working in JavaScript, so my main curiosity is whether this is not possible in TypeScript or am I doing something wrong.

6
  • Why not just use get add() in the Base class? Why assign it with Object.defineProperty? What is the actual point of installGetters()? Commented Dec 7, 2021 at 19:52
  • @VLAZ I actually have written the function installGetters() such that given an object, it creates multiple getters with the key as the getter name and the value as the return value. Commented Dec 7, 2021 at 19:55
  • 1
    That doesn't explain why it's needed. It's a class - you're supposed to inherit from it. If you don't, then why have a class in the first place? Choose one - have classes or don't. Mixing the approaches just leads to awkwardness. Commented Dec 7, 2021 at 19:57
  • Your trying to write traditional writing code, using a conceptual-style, Dynaamicly Prototype Orientated code, while changing to a Staticly Typed OOP language. Generally Speaking, methods like Argument.callee, Object.defineProperty(), are not type safe, and are conceptually Prototype Orientated, and not OO. If you want to use the code you demonstrated, which there is nothing wrong with it, you probably don't want to make the change to TypeScript. Just because everyone is on a TS bandwagon, doesn't mean that every JS dev needs to switch. I like TS, but I have always wrote OOP. Commented Feb 24, 2022 at 3:05
  • For someone use to writing code, like you showed, you either need to break your old JS habits, or just stick to JS. Thats my opinion anyway. Commented Feb 24, 2022 at 3:06

3 Answers 3

4

Although this is a pretty strange pattern, I'll provide an answer to your actual question.

TypeScript is not clever enough to infer the actual Base type based on a method called on a subclass constructor, so you have to declare it:

declare readonly add: number;

TypeScript playground

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

1 Comment

if the intent it to dynamically install getters (that is, to dynamic property names) then you could use [key: string]: unknown
3

Having applied inheritance, I would suggest using protected:

protected members are only visible to subclasses of the class they’re declared in.

class Base {
  protected add!: number;
  installGetters() {
    this.add = 5;
  }
}

Related issue to your problem: https://github.com/microsoft/TypeScript/issues/28694

2 Comments

This is the correct anwser. Because he is using an extended class to access the property via the install method. The snippet in this answer, and in the question, should preform similar enough to work for any means he needs to use it for. I actually would much rather use the code above as its much easier for the TSC compiler to follow. The Object.defineProperty method doesn't really work in a way that is harmonious with a statically typed system,
or with the benifits gained from the statically typed system. IMO, the whole point of typescript is to write more robust, solid code, which in this situation would be the snippet in the answer above.
-1

The reason to this is likely that typescript doesn't know about the getter you added. There is no typing telling typescript this getter exists and typescript is not able to magically know you added the getter function and what it would look like. Either you define the getter in the base class or in case this is not possible, there is probably no other way than casting this to any.

someAddition() {
  return 10 + (this as any).add
}

2 Comments

Using ‘any’ is a cop out
I know but do you have a better solution? I probably would just not write the code this way but if he wants to.

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.