Typescript - 如何声明具有已知属性的匿名对象?

Posted

技术标签:

【中文标题】Typescript - 如何声明具有已知属性的匿名对象?【英文标题】:Typescript - How to declare anonymous object with known properties? 【发布时间】:2018-07-04 01:18:28 【问题描述】:

在 JS 中,我的很多模块只是包装静态函数、枚举和属性的对象。例如,我有一个模块Debug 与此类似(我确实简化了它):

export default Debug = 
    // Current mode set, enum value from Modes. Setted outside of the module (see below).
    mode : null,

    // Enum of all possible modes
    Modes : 
        DEV : 0,
        PROD : 1,
    ,

    // getter, checks if it's in production mode
    get isInProdMode() 
        return Debug.mode === Debug.Modes.PROD;
    ,

    // If the condition is met, it will throw an error in development mode, or just silently log a warning in production mode
    assert : function(condition, message)
        if (condiftion) 
            if (Debug.isInProdMode)
                console.warn(message);
            else
                throw message;
        
    


// index.js
Debug.mode = Debug.Modes.DEV;

如何在 Typescript 中创建这样的匿名对象?使用枚举作为属性?还有一个getter函数?所有属性都是已知的。 我真的被困住了。

【问题讨论】:

此代码已经是有效的打字稿。你还需要它做什么? 【参考方案1】:

我倾向于解决这些场景的方法是只为匿名对象的属性创建接口,然后为匿名对象创建接口:

enum Modes 
    DEV     = 0,
    PROD    = 1,


interface IDebug 
    mode: Modes | null;
    Modes: typeof Modes;
    readonly isInProdMode: boolean;
    assert: (condition: boolean, message: string) => void;


const Debug: IDebug = 
    mode: null,
    Modes,
    get isInProdMode() 
        return Debug.mode === Debug.Modes.PROD;
    ,
    assert: (condition, message) => 
        if (condition) 
            if (Debug.isInProdMode) 
                console.warn(message);
             else 
                throw message;
            
        
    ,
;

export default Debug;

【讨论】:

const Debug: IDebug = Modes, // ... 我永远不会认为这是可能的。 Ô.Ô【参考方案2】:

我会说惯用的方法是使用命名空间。

namespace Debug 
  export enum Modes  DEV, PROD 

  export var mode: Modes = Modes.DEV;

  export function isInProdMode(): boolean 
    return mode === Modes.PROD;
  

  export function assert(condition: boolean, message: string) 
    if (condition) 
      if (isInProdMode()) 
        console.warn(message);
       else 
        throw message;
      
    
  
 

export default Debug

但是,命名空间不支持 getter 和 setter,因此需要将 getter 转换为常规函数。

如果需要将此代码声明为对象,则可以先定义枚举,然后从对象中引用。

enum Modes  DEV, PROD 

const Debug = 
  mode: Modes = Modes.DEV,
  get isInProdMode(): boolean 
    return Debug.mode === Modes.PROD;
  ,
  assert(condition: boolean, message: string) 
    // ...
  

【讨论】:

请停止使用 TypeScript 命名空间。它们阻止您使用 ES6 模块导入。是时候把那段悲伤的历史抛在脑后了! @LarsGyrupBrinkNielsen 听起来您将命名导出与默认导出混为一谈,并将其归咎于命名空间。默认导出对象与默认导出命名空间有所有相同的问题。 或者,如果您确定,请随意阅读 TypeScript 编译器的源代码,它大量使用命名空间作为一项功能,并告诉他们不要使用它。它们仍然是创建作用域类型的重要构造。 我说的是能够使用import someStuff from './some-es6-module';。如果您知道如何在具有命名空间的文件中执行此操作,请告诉我。从 ES6 模块访问命名空间的导出成员也是如此。 这是一个命名的导出,如果你像 OP 一样使用export default,那么对于对象或命名空间是不可能的。【参考方案3】:
// index.js
import Debug from './debug';

Debug.mode = Debug.Modes.DEV;
console.log(Debug.isInProdMode);
// false

【讨论】:

我的问题是关于转换调试模块。 对不起,我好像没听懂你的意思。 转换是什么意思? 例如,使Modes一个枚举。或者向assert 函数添加签名。我没能做到,因为它在一个匿名对象中,而不是在类声明中。但我从@pete 那里得到了答案。谢谢。

以上是关于Typescript - 如何声明具有已知属性的匿名对象?的主要内容,如果未能解决你的问题,请参考以下文章

您如何定义具有键字符串索引但具有特定类型的已知键的 TypeScript 接口?

TypeScript:如何声明记录或记录数组的类型?

如何迭代 TypeScript 中的已知属性键?

返回具有额外属性的 arg 的 TypeScript 函数 (TS2322)

如何实现类常量?

与接口同名的 TypeScript 类