假设我有一个可以从多个模块扩展的导出数组,例如:
// values.ts
export const values = [];
export function useValue(value) {
// ...
}
x
// module-1.ts
import { values } from './values.js';
values.push('foo', 'bar');
// @todo extend type
// module-2.ts
import { values } from './values.js';
values.push('baz');
// @todo extend type
// module-3.ts
import { useValue } from './values.js';
// (TS ERROR) should only accept: "foo" | "bar" | "baz".
useValue('qux');
的数据
是否可以创建一个(环境?)联合类型,通过向现有类型添加新值,可以由单个模块扩展?
我曾尝试使用接口和三重斜杠指令来实现预期的结果,但运气不佳。
我想要创建的是一个标签系统,其中核心功能由库模块提供,用户可以在应用程序的各个部分甚至其他库中引入自己的标签。但是,核心库应该看到引入的标签并正确验证所有函数调用。
1条答案
按热度按时间sg2wtvxw1#
据我所知,在你的库中获得这种类型扩展的唯一方法是将declaration merging与
interface
一起使用。(警告:我只是一个TypeScript的熟练工人。)你的库的类型可能看起来像这样(在你的
index.d.ts
或类似的文件中):字符串
注意
Value
的类型是如何从PossibleValues
接口的内容中派生出来的。这是关键点。我们不关心PossibleValues
中属性的类型,只关心它们的名称。然后,
module-1.ts
看起来像这样:型
使用声明合并将
foo
和bar
添加到接口,并将实际字符串推入values
。push
调用是有效的,因为"foo"
和"bar"
是Value
的一部分,因为它们被添加到PossibleValues
。然后
module-2.ts
做同样的事情:型
最后,让我们测试一下
module-3.ts
的用法:型
不幸的是,这本质上有点脆弱,因为扩展模块很容易扩展接口,但无法将值添加到
values
,使类型系统和运行时稍微不同步。(幸运的是,他们不会犯另一个错误-如果他们没有扩展接口,values
的类型不会让他们推送字符串。)在一条评论中,你问到如何在项目中测试它而不将
yourlib
作为一个单独的库。你可以通过将yourlib
作为一个模块并使用declare module
来扩展它来做到这一点:yourlib.ts
:型
注意,这不再是一个
.d.ts
文件,我们没有将它 Package 在declare module "yourlib"
中,我们为数组和函数提供了实际的运行时值。module-1.ts
:型
module-2.ts
:型
除了
import
(“from "./yourlib"
而不是from "yourlib"
”)外,module-3.ts
没有变化。