如何最好地模拟 Typescript 中的命名空间?
How to best emulate namespaces in Typescript?
我意识到命名空间在 ES6 中基本上已被弃用,并且在 Visual Code 中效果不佳。
但我还是想用它们。为什么?因为我的代码分布在多个文件中,所以我想在不创建它们之间的依赖关系的情况下对其进行分组。
这是用例。我在不同的文件中有两个不同的商店:
// fooStore.ts
class FooStore { numFoos = 0; }
export const fooStore = new FooStore();
和
// barStore.ts
class BarStore { numBars = 0; }
export const barStore = new BarStore();
出于可发现性目的,我想将这些商店组合在一起,以便开发人员可以参考 stores.fooStore
和 stores.barStore
。
一种解决方案是导出包含它们的对象,如下所示:
export const stores = {
fooStore,
barStore
};
这是有效的,但它有一个很大的缺点。如果任何代码引用 stores.
,那么所有引用的存储及其所有依赖项都会被拉入。为什么这是一个问题?因为我在一个代码库中工作,该代码库是 AngularJS 类(遗留代码)和 React/MobX 代码(我们要移植到的代码)的组合,而且我们的一些商店使用 AngularJS。当我编写单元测试或 Storybook 故事时,我不想为我什至不感兴趣的商店设置所有必要的依赖项。
我真正想做的是这样的事情,但我知道不建议这样做。那么我应该怎么做呢?
// fooStore.ts
class FooStore { numFoos = 0; }
namespace Stores {
export const fooStore = new FooStore();
}
我能想到 2 种平庸的方法来实现这一点,但它们都有缺点:
1。使用延迟 getter 在访问时加载商店。
const stores = {
get fooStore () {
return require("path/to/fooStore");
}
}
像这样的动态要求可能在您的构建步骤中表现不佳。
2。让商店在初始化时向商店的商店注册自己:
export const stores = {};
export class Store {
constructor(storeName) {
stores[storeName] = this;
}
}
这确实需要加载 FooStore
文件才能在商店中的商店中使用。
One solution is to export an object that contains them
是的,这会导致问题,因为它需要引入依赖项,才能将商店实例放入您的对象中。相反,为此使用带有命名导出的模块:
// stores/index.ts
export { fooStore } from './fooStore.ts';
export { barStore } from './barStore.ts';
然后你可以使用命名空间导入对它们进行分组:
import * as stores from 'stores';
console.log(stores.fooStore.numFoos);
这仍然允许 tree shaking - 上面的模块没有引用 stores.barStore
,因此不需要加载该模块(即使它被声明为依赖项)。
我意识到命名空间在 ES6 中基本上已被弃用,并且在 Visual Code 中效果不佳。
但我还是想用它们。为什么?因为我的代码分布在多个文件中,所以我想在不创建它们之间的依赖关系的情况下对其进行分组。
这是用例。我在不同的文件中有两个不同的商店:
// fooStore.ts
class FooStore { numFoos = 0; }
export const fooStore = new FooStore();
和
// barStore.ts
class BarStore { numBars = 0; }
export const barStore = new BarStore();
出于可发现性目的,我想将这些商店组合在一起,以便开发人员可以参考 stores.fooStore
和 stores.barStore
。
一种解决方案是导出包含它们的对象,如下所示:
export const stores = {
fooStore,
barStore
};
这是有效的,但它有一个很大的缺点。如果任何代码引用 stores.
,那么所有引用的存储及其所有依赖项都会被拉入。为什么这是一个问题?因为我在一个代码库中工作,该代码库是 AngularJS 类(遗留代码)和 React/MobX 代码(我们要移植到的代码)的组合,而且我们的一些商店使用 AngularJS。当我编写单元测试或 Storybook 故事时,我不想为我什至不感兴趣的商店设置所有必要的依赖项。
我真正想做的是这样的事情,但我知道不建议这样做。那么我应该怎么做呢?
// fooStore.ts
class FooStore { numFoos = 0; }
namespace Stores {
export const fooStore = new FooStore();
}
我能想到 2 种平庸的方法来实现这一点,但它们都有缺点:
1。使用延迟 getter 在访问时加载商店。
const stores = {
get fooStore () {
return require("path/to/fooStore");
}
}
像这样的动态要求可能在您的构建步骤中表现不佳。
2。让商店在初始化时向商店的商店注册自己:
export const stores = {};
export class Store {
constructor(storeName) {
stores[storeName] = this;
}
}
这确实需要加载 FooStore
文件才能在商店中的商店中使用。
One solution is to export an object that contains them
是的,这会导致问题,因为它需要引入依赖项,才能将商店实例放入您的对象中。相反,为此使用带有命名导出的模块:
// stores/index.ts
export { fooStore } from './fooStore.ts';
export { barStore } from './barStore.ts';
然后你可以使用命名空间导入对它们进行分组:
import * as stores from 'stores';
console.log(stores.fooStore.numFoos);
这仍然允许 tree shaking - 上面的模块没有引用 stores.barStore
,因此不需要加载该模块(即使它被声明为依赖项)。