【发布时间】:2022-01-17 15:22:30
【问题描述】:
问题
我们正在编写一个 npm 包,其中包含将在各种(内部)网站中使用的 React 组件。我们不得不在我们的 react .tsx 文件中使用一个有问题的 npm 包依赖项,它有以下问题:
- 尽管有
.d.ts文件,但它没有公开任何有用的类型...它们是空的。 - 它会在需要或导入服务器端时尝试运行,而不是等待直到被调用,因此我们必须避免顶级导入,而是执行
if (window) { const module = require('package-name') },然后仅在该块内使用它。 - 这是一个常见的错误来源,因此该库中的所有内容都需要在
try ... catch块内运行。
好吧,至少我们有类型
我们已经创建了自己的类型文件来解决问题 #1:
// problematic-package-types.d.ts
declare module 'problematic-package' {
function doErrorProneButNecessaryThing(
foo: Record<string, unknown>,
bar: string
): void
}
所需的解决方案
长期解决方案是修复这个有问题的库,我们正在研究如何完成(但它不在我们的直接控制范围内)。
不过,在短期内,我们现在需要一个解决方案。
请注意,我们在我们的 npm 包捆绑器中配置动态需求以仅在使用时导入它们,而不是像其他导入/需求一样对待它们。由于我们的包在其他应用程序中使用,我们无法完全控制该应用程序捆绑的工作方式或何时需要组件,因此我们的组件可能最终在不应该被需要时被服务器端需要,我们必须容忍它。我们仍在了解这方面的某些方面。
我的狂野(但失败)刺
我的目标是做一些像这样更 DRY 的事情,我们解决强类型、检测服务器端执行和什么都不做以及添加错误处理这三个问题:
// hoping to leverage our module declaration above without importing anything
import type * as ProblematicPackage from 'problematic-package'
import wrapProblematicRequire from '../utils/my-sanity-preserving-module'
const wrappedProblematicPackage = wrapProblematicRequire<ProblematicPackage>()
// then later...
const foo: Record<string, unknown> = { property1: 'yes', property2: false }
const bar = 'yodeling'
wrappedProblematicPackage.invokeIfWindowReady(
'doErrorProneButNecessaryThing',
foo,
bar
)
但是,TypeScript 不喜欢 import type,这很遗憾:
不能使用命名空间“ProblematicPackage”作为类型。
恳求
如何获取我们放入 problematic-package-types.d.ts 的类型信息以根据需要使用?
或其他任何东西。老实说,我对任何事情都持开放态度,无论多么粗俗或骇人听闻,只要我们在呼叫站点获得一些清晰和可靠的信息,并提供所描述的完整类型信息。建议/建议?
详细信息
这是wrapProblematicRequire 函数的完整实现。我没有测试过。这可能很糟糕。我敢肯定它可能会好得多,但我现在没有时间让这个帮助模块超级干净。 (我处理函数类型信息的尝试不太正确。)
type Func = (...args: any[]) => any
type FunctionNames<T, TName extends keyof T> = T[TName] extends Func ? TName : never
type FunctionNamesOf<T> = FunctionNames<T, keyof T>
const wrapProblematicRequire = <T>(packageName: string) => ({
invokeIfWindowReady<TName extends FunctionNamesOf<T>>(
name: T[TName] extends Func ? TName : never,
...args: T[TName] extends Func ? Parameters<T[TName]> : never
): T[TName] extends Func ? ReturnType<T[TName]> : never {
if (!window) {
// @ts-ignore
return undefined
}
try {
// @ts-ignore
return require(packageName)[name] as T[TName](...args)
} catch (error: unknown) {
// ToDo: Log errors
// @ts-ignore
return undefined
}
}
})
export default wrapProblematicRequire
附: await import('problematic-package') 似乎没有用。是的,问题比比皆是。
【问题讨论】:
标签: node.js reactjs typescript