问题描述
我正在将我的 React 组件库 react-esri-leaflet 转换为打字稿。该库要求用户安装 react-leaflet 作为 peerDependency,并提供对 react-leaflet version 3 (RLV3) 和 react-leaflet version 2 (RLV2) 的支持。对于默认组件,我可以简单地做
import { createLayerComponent } from 'react-leaflet'
但是如果用户想要使用兼容 RLV2 的组件,他们可以单独导入这些组件(请随意查看库文档以了解如何)。大多数 RLV2 组件都以类似
import { withLeaflet,MapControl } from 'react-leaflet'
在转换为打字稿时,这会引发错误。在开发这个库时,我安装的 react-leaflet 安装了最新版本。 withLeaflet
和 MapControl
在该版本中不再存在。
为了解决这个问题,我遵循了 this answer 中的建议“Node 应用程序中相同的 npm 包的两个版本”。这允许我通过将 RLV2 别名为 'react-leaflet-v2'
来将 RLV2 视为源代码中的一个单独包,我可以这样做
import { withLeaflet,MapControl } from 'react-leaflet-v2'
太好了,现在打字稿很高兴,我可以将适当版本的 react-leaflet 导入适当的组件,并且打字正确。但是,当我使用 tsc
编译回 js 时,我的 V2 组件中使用的包名称仍然是 'react-leaflet-v2'
。
问题在于库的最终用户将使用 RLV2 或 RLV3,并且在他们的项目中将简单地称为 'react-leaflet'
。库的编译文件需要能够找到 'react-leaflet'
,而不是某些别名,无论它们使用的是什么版本。
如何在开发中为两个依赖版本保持类型安全,但让我的用户不用担心,这意味着只需安装他们想要使用的 react-leaflet 版本,从库中导入正确的组件,以及组件是否在其项目中找到了 'react-leaflet'
依赖项?编译时是否可以告诉 tsc
将 'react-leaflet-v2'
重命名为 'react-leaflet'
?还有其他解决方案吗?
解决方法
所以我想出了一个办法。它并不完美,但基本上是:
使用 Babel
我没有使用 tsc
转译我的 ts 文件,而是使用了 babel,仅用于那些具有别名节点模块导入的文件。我找到了 babel-plugin-transform-rename-import,它可以在编译时重命名导入。将它添加到标准 babel 配置中,我有这个:
{
"presets": ["@babel/preset-env","@babel/preset-typescript"],"plugins": [
"@babel/plugin-proposal-object-rest-spread","transform-react-jsx","@babel/plugin-proposal-class-properties",[
"transform-rename-import",// <--- solution here
{ "original": "react-leaflet-v2","replacement": "react-leaflet" }
]
]
}
这是 react 打字稿文件的标准设置,带有一些额外的 bella 和 whistle。如您所见,它会将所有导入从“react-leaflet-v2”重命名为“react-leaflet”。
考虑到我的项目被组织为将所有这些 RLV2 文件都放在它们自己的文件夹中,我编写了一个脚本来使用常规的 tsc
命令来编译所有常规组件,但是使用带有该配置的 babel 只转换v2 目录中的文件。然后我使用 tsc --emitDeclarationOnly true
为 v2 文件编写 .d.ts
文件。
注意这很有效,因为我的库没有从“react-leaflet-v2”导入任何纯打字稿声明,这意味着没有 import { TypeOrInterfaceOrEnum } from 'react-leaflet-v2'
- 所有导入都只是组件或函数。如果我从 react-leaflet-v2 导入类型信息,我的 import something from 'react-leaflet-v2'
文件中仍然会有 .d.ts
,我也需要以某种方式转换它们。也许 babel 也可以做到这一点,但我现在没有必要去探索它。