如何在TypeScript中使用Object.defineProperty来创建getter函数?

4
我在JavaScript中使用了下面给出的实现。
class Base {
    installGetters() {
        Object.defineProperty(this, 'add', {
            get() {
                return 5;
            }
        });
    }
}

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

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

我在父类函数Base中定义了getter属性add,并在子类构造函数中调用installGetters()函数后,在子类New中使用了该属性。这在JavaScript中有效,但在TypeScript中会导致this.add出错。希望能得到帮助。

我这么做的主要动机是想将一个对象传递给installGetters()函数,以便它可以生成多个getter,其中对象键是getter名称,而值则来自相应的getter函数。

这在JavaScript中是有效的,因此我的主要好奇心是这是否不可能在TypeScript中实现,还是我做错了什么。


为什么不直接在Base类中使用get add()呢?为什么要用Object.defineProperty进行赋值?installGetters()的实际作用是什么? - VLAZ
@VLAZ,我实际上已经编写了函数installGetters(),它可以创建多个getter,其中键作为getter名称,值作为返回值。 - Sayantan Ghosh
1
那并没有解释为什么它是必需的。它是一个类 - 你应该从中继承。如果你不这样做,那么为什么一开始要有一个类呢? 选择一个 - 要么有类,要么没有。混合使用方法只会导致笨拙。 - VLAZ
你试图编写传统的写作代码,使用概念风格的动态原型导向代码,同时转换为静态类型的面向对象语言。一般来说,像Argument.callee、Object.defineProperty()这样的方法不是类型安全的,而且在概念上是原型导向的,而不是面向对象的。如果你想使用你展示的代码,那么没有任何问题,你可能不想改用TypeScript。并不是每个JS开发人员都需要切换到TS,只是因为大家都在TS的浪潮中,我喜欢TS,但我一直写OOP。 - JΛYDΞV
对于习惯编写代码的人,就像你展示的那样,你要么需要打破旧的JS习惯,要么就坚持使用JS。这是我的观点。 - JΛYDΞV
我个人非常喜欢TypeScript,并且会用TS编写代码而不是JS,但是这并不是完美无缺的。虽然TS有其优点,但大多数开发者对TypeScript的评价有些夸大了其伟大之处。TS的每一个优势都有其成本。如果你真的需要在你的项目中实现问题片段,那么也许TS不是适合该项目的语言。 - JΛYDΞV
3个回答

4

虽然这是一个相当奇怪的模式,但我会回答你的实际问题。

TypeScript 不够聪明,无法根据在子类构造函数上调用的方法推断出实际的 Base 类型,因此您必须进行 declare 声明:

declare readonly add: number;

TypeScript playground

TypeScript游乐场

如果意图是动态安装getter(即动态属性名称),那么您可以使用[key: string]: unknown - roberto tomás

2

这是正确的答案。因为他使用扩展类通过install方法访问属性。此答案中的代码片段和问题中的代码片段应该足够相似,以便于他需要使用它的任何方式都可以工作。实际上,我更喜欢使用上面的代码,因为TSC编译器更容易跟踪。Object.defineProperty方法并不真正与静态类型系统协调工作。 - JΛYDΞV
通过使用静态类型系统,我们可以获得更多的好处。在我看来,TypeScript 的整个目的就是编写更加健壮、稳定的代码,而这种情况下的代码片段正是上面答案中所示的。 - JΛYDΞV

0
这可能是因为 TypeScript 不知道你添加的 getter。没有类型告诉 TypeScript 这个 getter 的存在,TypeScript 也不能神奇地知道你添加了 getter 函数以及它的样子。要么你在基类中定义 getter,要么如果不可能的话,就只能将其转换为 any 类型。
someAddition() {
  return 10 + (this as any).add
}

3
使用“任何”是逃避责任的表现。 - Daniel A. White
我知道,但你有更好的解决方案吗?我可能不会这样编写代码,但如果他想要的话。 - fragsalat

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接