编译后,访问TypeScript中已声明(但未导出)模块中的枚举

时间:2018-10-15 12:57:43

标签: typescript

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子句来访问枚举(并因此在所有位置显式导入模块)?有没有我没有遵循的良好做法?

1 个答案:

答案 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;
        }
    };
});