【发布时间】:2020-03-26 21:49:50
【问题描述】:
我正在寻找一种方法来减少我的 NodeJS 后端的样板代码。在龙目岛有例如可以通过注解为对象注入构造函数和 getter/setter。
有没有办法在 TypeScript 中做到这一点?
【问题讨论】:
标签: javascript node.js typescript lombok
我正在寻找一种方法来减少我的 NodeJS 后端的样板代码。在龙目岛有例如可以通过注解为对象注入构造函数和 getter/setter。
有没有办法在 TypeScript 中做到这一点?
【问题讨论】:
标签: javascript node.js typescript lombok
我快速搜索了一下,发现像 this 这样的项目试图为 TypeScript 带来类似 Lombok 的功能,但正如你所见,这些项目很少见,并且没有被广泛使用。这意味着一个问题:您为什么需要这样的工具?
TS 在减少样板代码方面已经相当不错了。当我定义一个类时,我通常会这样做:
class A {
constructor(private fieldA: string, private readonly fieldB = 0) {}
}
这很简洁,不是吗?我猜您是在将 TS 的功能与 Java 的功能进行比较。 Java 非常冗长,Lombok 对此有很大帮助。但是 TS 和 JS 是不同的,虽然 Lombok 解决的一些问题已经被 TS 解决了,但其他问题在 TS 和 JS 的世界里都不是问题。
首先,上面的语法创建具有访问修饰符的特定类型的类字段,您还可以在fieldB 前面发现readonly 关键字及其默认值0。最重要的是,它们与构造函数一起创建,构造函数在执行时隐式地为实例字段分配值(请参阅,没有this.fieldA = fieldA)。所以这已经不仅仅涵盖了 Lombok 注入构造函数的能力。请注意:在 JS 中(因此在 TS 中),您只能有一个构造函数。 JS 不支持方法重载。
现在关于 getter/setter,它们在 JS(或 TS)中的使用方式与在 Java 中的使用方式不同。在 JS 中,直接使用字段是一种规范,setter 和 getter 仅在您想要的特殊情况下使用:
readonly,编译器将确保您不分配给该属性 - 无需使用吸气剂。如果您在没有编译时检查的情况下使用 JS 进行开发,则惯例是用下划线标记私有属性(您绝对不应该修改的属性)。无论哪种方式,您仍然可能修改您不应该修改的变量,但与 Java 不同,这不被认为是足以在 JS(和 TS)中随处使用 get/set 的理由。相反,如果您确实需要确定在运行时不会发生任何修改,您可以使用前面提到的不带 setter 的 getter,或者将对象的属性配置为不可写。()。现在因为这个逻辑是自定义的,所以不能仅仅通过注解来生成。如您所见,Lombok 在 Java 中处理的一些问题已经在 TS 中处理了,而另一些则不是问题。
编辑 5-9-2021 - 回答 @Reijo 的问题: Lomboks 的功能超越了 getter/setter/constructors。查看@Builder 注释,我很想知道您对此有何看法。
如果问题只是关于是否有一个 TypeScript/JavaScript 库提供或多或少与 Lombok for Java 相同的实用程序集合,据我所知,答案是否定的。我认为部分原因是 TypeScript 提供了开箱即用的功能(正如我在上面已经概述的那样),这让我回到了 Java 比 TypeScript 或 Groovy 等语言更需要 Lombok 的观点。当您需要 TS 不提供的东西时,例如构建器模式,您可以使用库来解决特定问题,例如 builder-pattern(在其核心中使用 JS 代理)或感谢 JS 的灵活特性(实际上是 TS ) 自己轻松编写。
这一切都很好,但您可能希望以更具声明性的方式添加功能 - 通过注释(在 TS 世界中,它们被称为 decorators,它们的工作方式不同),就像 Lombok 所做的那样。这可能会很复杂。
首先,如果您在 TS 中通过装饰器修改类型,TS 编译器将无法识别更改。因此,如果您通过在装饰器中添加一个方法来扩充类,TS 将无法识别该新方法。有关详细信息,请参阅此discussion。
这意味着您要么放弃装饰器并使用函数来修改类型(您可以),要么深入研究 AST。这就是龙目岛的工作方式。它在称为注释处理的编译阶段采用带注释的类型,并且由于 javac(和 Eclipse 编译器)中的 hack 修改了它们的 AST(例如,为给定的类创建内部构建器)。使用 TS/JS 可以采用类似的方式。
虽然在 TS 和 JS 中没有像注释处理这样的东西,但您仍然可以创建一个构建步骤,该步骤获取源代码并修改它的 AST 以实现您的目标(这也是 Babel 的工作方式)。这可能会导致基于使用的注解(广义上 - 不一定是装饰器)向类添加方法、生成构建器等。
不过,这种方法是一个挑战。除了 AST 是一个高级主题之外,即使你让它工作,你也需要你的 IDE 的支持,现在这也意味着语言服务器的支持。这不适合胆小的人。
但是,如果您打算为 TS 创建像 Lombok 这样的东西,我的编辑不应该吓跑任何人,因为似乎有些人希望在 TS/JS 世界中看到它。它应该只向您展示前面的内容;)。
【讨论】:
Builder<T>,在类上遇到装饰器,为该类生成方法builder(),并为带注释的类生成实现 Builder