TL; DR
不导出名称空间,而只声明它,我想访问其中的一个枚举。编译后,将无法访问名称空间(它是未定义的对象),因此无法访问枚举(名称空间错误)。
说明
我正在用TypesScript建立一个项目,我想避免导入所有特定于该项目的定义。在此代码段中,我创建了一个名称空间,在其中放置我的redux逻辑的本地定义。
redux声明( redux.d.ts )的摘录:
declare namespace Redux {
namespace Actions {
enum TypeKeys {
REDUX_INIT = '@@redux/INIT',
BOOTSTRAP = 'BOOTSTRAP',
CORPUS_LOADED = 'CORPUS_LOADED',
...
}
...
interface Definition {
doSomething(): void;
...
}
...
}
namespace Store {
interface Definition { ... }
...
}
}
允许我避免在所有代码中导入定义(例如,在顶级组件的const mapStateToProps = (state: Redux.Store.Definition) => state;
中导入,而不必导入任何 Redux 名称空间)。
为了解决这个问题,我编写了这个reducer( corpusReducer.ts 摘录):
// Note: no need to import Redux!
export default (state: Redux.Store.CorpusManagement, action: Redux.Actions.ActionTypes): Redux.Store.CorpusManagement => {
switch (action.type) {
case Redux.Actions.TypeKeys.CORPUS_LOADED:
return { corpus: action.payload };
default:
return state === undefined ? { corpus: { documents: [] } } : state;
}
};
一旦被编译,我将得到错误 ReferenceError:未为行case Redux.Actions.TypeKeys.CORPUS_LOADED
定义Redux 。
我怀疑Redux
在运行时不可用,因为由于命名空间,它属于TypeScript世界。另一方面,TypeKeys
是一个枚举,应该在JavaScript中具有一个映射,因此,我的预期行为是,一旦被编译,该枚举仍然可以访问。
如果添加导出(将行更改为declare namespace Redux
),该文件将被“提升”为模块,但随后需要将其导入代码中的所有位置。
问题
如何避免使用export子句来访问枚举(并因此在所有位置显式导入模块)?有没有我没有遵循的良好做法?
答案 0 :(得分:1)
枚举使用枚举对象在运行时保存值。这意味着,如果无法访问此对象,则依赖于它的存在的代码将在您发现时失败。
您最好的解决方案是确保导出对象。添加一个额外的模块来保存枚举并将其导入。
如果这不可能,则可以在声明中使用const枚举。常量枚举不依赖于对象的存在,因为每当编译器遇到对枚举值的引用时,实际值将被硬编码在生成的JS中。
const enum TypeKeys { // No code for const enums is generated.
REDUX_INIT = '@@redux/INIT',
BOOTSTRAP = 'BOOTSTRAP',
CORPUS_LOADED = 'CORPUS_LOADED',
}
let d = TypeKeys.BOOTSTRAP; // All enum references are replaced with values, so this becomes var d = "BOOTSTRAP"
您应该谨慎使用此方法,因为这意味着所有值都在JS中进行了硬编码,对枚举的任何更改都将要求您重建引用枚举的任何代码。
修改
适用于我的完整代码:
// definitions.d.ts
declare namespace Redux {
namespace Actions {
const enum TypeKeys {
REDUX_INIT = '@@redux/INIT',
BOOTSTRAP = 'BOOTSTRAP',
CORPUS_LOADED = 'CORPUS_LOADED',
}
interface Definition {
doSomething(): void;
}
interface ActionTypes {
type: TypeKeys
payload: any;
}
}
namespace Store {
class CorpusManagement {}
}
}
// usage.ts
/// <reference path="./definitions.d.ts" />
export default (state: Redux.Store.CorpusManagement, action: Redux.Actions.ActionTypes): Redux.Store.CorpusManagement => {
switch (action.type) {
case Redux.Actions.TypeKeys.CORPUS_LOADED:
return { corpus: action.payload };
default:
return state === undefined ? { corpus: { documents: [] } } : state;
}
};
输出:
(...)
(function (require, exports) {
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
/// <reference path="./definitions.d.ts" />
exports.default = (state, action) => {
switch (action.type) {
case "CORPUS_LOADED" /* CORPUS_LOADED */:
return { corpus: action.payload };
default:
return state === undefined ? { corpus: { documents: [] } } : state;
}
};
});