为什么要在DefinitelyTyped上发布JavaScript库的TypeScript声明文件?

13
我在npm上发布了两个JavaScript库,用户要求为这两个库提供TypeScript类型定义。我自己不使用TypeScript,也没有重写这些库的计划,但我仍然想添加类型定义文件,以便更好地实现代码智能提示。我需要一些建议。
我开始阅读DefinitelyTyped项目发布npm包的声明文件文档。这两个来源都表明,“发布到npm上的@types组织”是非TypeScript项目的首选方法。
为什么比起通过package.json中的types字段与库一起发布类型定义,这种方式更受欢迎?我真的不明白为什么要涉及第三方。这样更新类型定义和版本控制似乎更加复杂。
以上引用来自上述文档(重点是我的):
来自DefinitelyTyped:
如果您是库的作者并且您的包是使用TypeScript编写的,请将自动生成的声明文件捆绑在您的包中,而不是发布到Definitely Typed。
来自typescriptlang.org:
现在你已经按照本指南的步骤编写了一个声明文件,是时候将其发布到npm上了。有两种主要的方法可以将你的声明文件发布到npm上: - 与你的npm包捆绑 - 发布到npm上的@types组织。
如果你的包是用TypeScript编写的,那么首选第一种方法。使用--declaration标志生成声明文件。这样,你的声明和JavaScript将始终保持同步。
如果你的包不是用TypeScript编写的,则第二种方法是首选。
if (isAuthor && lang === "typescript")
  bundle();
else
  publishOnDefinitelyTyped();

4
即使一个包是纯JavaScript编写的,如果包作者自己维护声明文件,那么它们应该作为包的一部分进行分发。许多库都这样做,比如moment库,这极大地简化了作者和他们的依赖方的版本控制和依赖管理。我认为你正在阅读的指南预设了您无法控制被打字的包,并将其应用得过于广泛。 - Aluan Haddad
@AluanHaddad,你说的完全符合我的想法。我没有看过moment.js,但我看到一些用JS编写的核心Vue.js插件也发布了自己的声明文件,就像你描述的那样。也许我读错了引语,但我理解它们至少意味着DefinitelyTyped是首选。尽管没有给出任何理由... - bernie
1
顺便说一下,即使它没有回答你的问题,我只是告诉你,如果文档写得好,你可以从文档中生成类型定义。所以也许需要的工作量比你想象的要小。 - Christian Vincenzo Traina
@Bernie,你是否接受定义的贡献?我很乐意加入。 - Avin Kavish
@AluanHaddad 如果你把这个写成一个答案,我会接受它。 - bernie
@UniqIdentifierAssignedAtBirth 好的,那太好了!请看这里:https://github.com/berniegp/mock-xmlhttprequest/issues/13#issuecomment-508450764 抱歉回复晚了,我需要设置一些东西。 - bernie
1个回答

7

在类型声明发布指南方面,有些地方似乎过时了且不够详细。

我将尝试详细比较这两种情况。

1. 将类型与npm包捆绑在一起

1.1. 从包使用者的角度来看

1.1.1. 优点

总体而言,打包的类型更加便利,因为可以简化依赖管理。

  • 无需额外的@types依赖(添加包依赖)
  • 无需同步包和其类型之间的版本(升级包依赖)

1.1.2. 缺点

  • 没有多少选项可供选择不使用打包的类型

    这涉及到消费者需要修改或替换类型声明的情况。

    在具有有见地的构建设置的项目中,由于已经有限的配置选项,该过程可能会产生相当大的问题。

1.2. 从包作者的角度来看

1.2.1. 优点

  • 库所有者可以随意发布类型声明的补丁和更新,以任何频率或计划
  • 没有第三方或外部类型依赖的限制
  • 提供多个版本的并行支持与实际代码的处理方式相同

1.2.2. 缺点

将类型与包捆绑在一起意味着每次发布版本时实际上会发布两个API协议。

例如:

假设存在一个旨在符合semver版本控制的库。

  • 最新版本 -> 1.0.0
  • 由于重大更改而增加主要版本 -> 2.0.0
  • 报告了类型声明中的关键错误,对typescript项目的一组用户来说,该版本已经损坏
  • 类型的修复是一个破坏性更改

下个版本的选项有:

A. 2.X.X -> 违反类型声明的semver规则

B. 3.0.0 -> 违反实际代码的semver规则

很可能存在许多这样的情况变体。

2. 发布到Definitely typed仓库

2.1. 从包使用者的角度来看

2.1.1. 优点

  • 通过删除@types依赖项进行简单的选择退出

2.1.2. 缺点

  • 包使用者负责保持包及其相关类型版本的同步

2.2. 从包作者的角度来看

2.2.1. 优点

  • 类型对软件包的发布周期没有影响。

  • DT存储库附带两个额外特性:

    • dts-lint 库用于类型断言和类型测试
    • 深度性能和编译器占用分析,包括最新软件包版本和经过PR修改后软件包之间的差异。

    第一个工具可以轻松地合并到另一个软件包存储库中。 我不确定分析是否可以在自己的存储库中进行复制,但它包含了大量有价值的数据。

2.2.2. 缺点

  • 非标准支持过去版本的方式

  • 类型发布计划受DT审查和发布周期的限制

    假设 DefinitelyTyped PR 的创建者是 @types 软件包所有人,通常需要将 PR 合并前花费一到两天时间。此外,在 types-publisher 更新与PR相关的@types npm软件包之前存在轻微延迟。

    如果 PR 是作者对给定软件包的首次贡献,则涉及到额外的审核过程。

  • 使用外部依赖项

    TypeScript 手册说:

    如果您的类型定义依赖于另一个软件包:

    不要将其与您的类型定义组合在一起,保持各自在其自己的文件中。

    也不要将声明复制到您的软件包中。

    如果它没有打包其声明文件,请依赖于npm类型声明软件包。

    根据冗余实用类型的数量来判断,这些几乎不被尊重。

    类型声明的作者允许使用相邻的 DT 存储库类型。从此列表之外的软件包依赖需要它们在types-publisher白名单上。 新软件包可以通过向 types-publisher 提交 PR 来列入白名单。 我的 PR 被合并花费了两个多星期的时间。我不知道是否正常,因为我只提交了一个PR。

  • DT存储库容量

    我没有跨IDE比较或经验,但就JetBrains IDE而言,完全索引的DT存储库项目的内存占用使IDE无法使用。

    禁用更改时的重新编译可以在一定程度上帮助。通过删除与感兴趣的软件包无关的 DT 存储库内容,可以避免令人沮丧的 IDE 体验。


1
很棒的写作。我认为,JS模块提供的类型声明中的一个错误(例如,帮助代码完成)不足以触发包本身的主要版本升级。我猜这不符合严格的semver规范,但我认为它提供了一个更符合库实际使用的发布编号方案。 - bernie
虽然版本示例显然是边缘情况,但它并非完全假设,并且 - 如前所述 - 不符合 semver 规范。此外还有... - Tomasz Zabłocki
我认为系统吃掉了你评论的最后一部分! - bernie
1
@bernie,显然是这样的。最后一部分提到类型声明对于TypeScript优先开发人员至关重要,因为这是编译错误而不是缺少代码完成的问题。 - Tomasz Zabłocki

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