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.

Sayantan Ghosh
  • 368
  • 5
  • 22
  • Why not just use `get add()` in the `Base` class? Why assign it with `Object.defineProperty`? What is the actual point of `installGetters()`? – VLAZ Dec 07 '21 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. – Sayantan Ghosh Dec 07 '21 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. – VLAZ Dec 07 '21 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. – JΛYDΞV Feb 24 '22 at 03: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. – JΛYDΞV Feb 24 '22 at 03:06
  • I personally love TypeScript, and I write TS over JS, however, its not all unicorns sunshine & rainbows. TS has benefits sure, but most of the developers that rant about how great TypeScript is, over exaggerate its greatness. Every benefit TS has comes at a cost. If you really need to implement the snippet in your question, maybe TS isn't the write language for that project. – JΛYDΞV Feb 24 '22 at 03:14

3 Answers3

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

Guerric P
  • 30,447
  • 6
  • 48
  • 86
  • if the intent it to dynamically install getters (that is, to dynamic property names) then you could use `[key: string]: unknown` – roberto tomás Dec 07 '21 at 20:35
2

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

Majed Badawi
  • 27,616
  • 4
  • 25
  • 48
  • 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, – JΛYDΞV Feb 24 '22 at 03:21
  • 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. – JΛYDΞV Feb 24 '22 at 03:22
0

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
}
fragsalat
  • 500
  • 4
  • 14