为啥要在 DefinitiveTyped 上为 Javascript 库发布 TypeScript 声明文件?

Posted

技术标签:

【中文标题】为啥要在 DefinitiveTyped 上为 Javascript 库发布 TypeScript 声明文件?【英文标题】:Why publish the TypeScript declaration file on DefinitelyTyped for a Javascript library?为什么要在 DefinitiveTyped 上为 Javascript 库发布 TypeScript 声明文件? 【发布时间】:2019-11-12 00:32:57 【问题描述】:

我在 npm 上发布了两个 javascript 库,用户要求为它们提供 TypeScript 类型定义。我自己不使用 TypeScript,也没有计划在 TypeScript 中重写这些库,但如果只是为了更好地完成 IntelliSense 代码,我仍然想添加类型定义文件。我正在为此寻求一些建议。

我开始阅读DefinitelyTyped project 的文档和publishing a declaration file for an npm package 的文档。两个消息来源都指出,“在 npm 上发布到 @types 组织”是非 TypeScript 项目的首选方法。

为什么这比通过package.json 中的types 字段与库本身一起发布类型定义更受欢迎?我真的不明白让第三方参与其中的意义。似乎更新类型定义和版本化它们只是这样更复杂。

上面引用的文档中的引用(强调我的)

来自DefiniteTyped:

如果你是库作者并且你的包是用TypeScript编写的捆绑自动生成的声明文件在你的包中而不是发布到绝对类型。

来自 typescriptlang.org:

现在您已经按照本指南的步骤编写了声明文件,是时候将其发布到 npm。您可以通过两种主要方式将声明文件发布到 npm:

与你的 npm 包捆绑,或者 在 npm 上发布到 @types 组织。

如果您的包是用 TypeScript 编写的,那么 第一种方法 更受青睐。使用 --declaration 标志生成声明文件。这样,您的声明和 JavaScript 将始终保持同步。

如果您的包不是用 TypeScript 编写的,那么 第二种 是首选方法。

两者似乎都在说:

if (isAuthor && lang === "typescript")
  bundle();
else
  publishOnDefinitelyTyped();

【问题讨论】:

即使一个包是用纯 JavaScript 编写的,如果包作者自己维护声明,它们也应该作为它的一部分分发。许多库都这样做,例如 moment,它极大地简化了作者及其依赖者的版本控制和依赖关系管理。我认为您正在阅读的指南假定您不控制正在输入的包并且应用它们过于广泛。 @AluanHaddad 你所说的完全符合我的想法。我没有看moment.js,但是我看到一些用JS编写的核心Vue.js插件也像你描述的那样发布了自己的声明文件。也许我读错了引号,但我理解它们至少暗示着肯定类型是首选。虽然没有给出任何理由...... 顺便说一句,即使它没有回答你的问题,我只是告诉你,如果它们写得好,你可以从文档中生成类型定义。所以也许它需要的努力比你想象的要小 @bernie 您是否接受对定义的贡献?我很乐意参加 @AluanHaddad 如果你写这个作为答案,我会接受它 【参考方案1】:

类型声明发布指南在几个方面似乎有点过时和稀疏。

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

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。发布到确定类型的存储库

2.1。从包装消费者的角度来看

2.1.1。优点

通过删除 @types 依赖项简单地选择退出

2.1.2。缺点

包消费者负责保持包和相关类型的版本同步

2.2。从包作者的角度来看

2.2.1。优点

类型对包的发布周期没有影响

DT repo 带有两个额外的特征:

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

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

2.2.2。缺点

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

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

假设DefinitelyTyped PR 创建者是@types 包所有者,它通常 在 PR 合并之前需要一到两天的时间。此外,还有一个小 types-publisher 更新 PR 相关 @types npm 包之前的延迟。

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

使用外部依赖项

TypeScript 手册说:

如果你的类型定义依赖于另一个包:

不要把它和你的结合起来,把它们放在各自的文件里。

也不要复制包中的声明。

如果 npm 类型声明包不打包其声明文件,请依赖它。

从冗余实用程序类型的数量来看,这些几乎没有受到尊重。

类型声明的作者可以使用相邻的 DT 存储库类型。 取决于此列表之外的包,要求它们在类型发布者白名单上。

可以通过向 types-publisher 提交 PR 来将新包列入白名单。 我的 PR 花了两个多星期才被合并。我不知道这是否正常,因为我提交了一个 PR。

DT 回购量

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

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

【讨论】:

很棒的文章。我认为 JS 模块提供的类型声明中的错误(例如帮助代码完成)不足以触发包本身的主要版本碰撞。我想这不符合严格的 semver,但我认为它提供了一个更符合库的实际使用的版本编号方案。 虽然版本示例显然是一种极端情况,但它并不完全是假设性的,并且 - 如前所述 - 不符合 semver。另外还有 我认为系统吃掉了你评论的最后一部分! @bernie,显然做到了。最后一部分提到类型声明对于 typescript-first 开发人员来说至关重要,因为这是一个破坏编译而不是缺少代码完成的问题。

以上是关于为啥要在 DefinitiveTyped 上为 Javascript 库发布 TypeScript 声明文件?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在反应历史 createHashHistory 上为每个路径附加 /#?

为啥我不能使用 CAKeyframeAnimation 在 eulerAngle 上为 SCNnode 设置动画

为啥在 Heroku 服务器上为 Laravel JWT 身份验证收到此错误

为啥我不能在我的 XAMPP 上为这个 PHP 网站设置虚拟主机?

尽管没有任何错误或异常,为啥 Stripe Google Pay 按钮无法在 UI 上为我呈现?

为啥 SKStoreProductViewController loadProductWithParameters 不会在 iOS 8.0.2 上为 Apple App Testers 调用其 com