如何键入访问深层对象的属性-动态获取对象密钥

时间:2019-07-29 12:30:51

标签: typescript

我想根据提供的键名获得正确的类型来访问对象属性。我想在下面获得对象的键。

我有以下对象,我想从中访问一些数据:

const source = {
  sth: {
    EXAMPLE: 'this is my example'
  },
  another: {
    TEST: 'this is my test value'
  }
};

访问功能:

function getMessage(context : keyof typeof source, msgKey: string) : string {

    if(msgKey in source[context]) {
      return source[context][msgKey]
    }
}

通过keyof typeof source,我得到了一级密钥-就像一个护身符。

如何获取较低级别的密钥?当然有了msgKey: string时我会出错:

  

元素隐式具有'any'类型,因为类型'string'的表达式不能用于索引类型'{例如:string; } | {TEST:字符串; }'。     在类型'{上找不到参数类型为'string'的索引签名。 } | {TEST:字符串; }'

当然,我想getMessage('sth', 'EXAMPLE')拿到'this is my example'

1 个答案:

答案 0 :(得分:1)

根据编译器提示

  

在类型'{上未找到参数类型为'string'的索引签名。 } | {TEST:字符串; }'

您需要为source的属性指定索引签名:

interface Source {
  [key: string]: {  // First level
    [key: string]: string; // Second level
  }
}

const source: Source = {
  sth: {
    EXAMPLE: 'this is my example'
  },
  another: {
    TEST: 'this is my test value'
  }
};

现在,您甚至不需要为第一级编写keyof typeof source,因为已经从Source界面中隐含了它:

function getMessage(context: string, msgKey: string): string {
  if(msgKey in source[context]) {
    return source[context][msgKey]
  }
}

更深层次

据我了解,无法为任何动态嵌套级别指定索引签名,因此您必须为每个级别显式指定索引签名。但是,使用泛型可以使事情变得简单一些:

type Indexed<T> = {
  [key: string]: T;
}

const source: Indexed<Indexed<string>> = {
  sth: {
    EXAMPLE: 'this is my example'
  },
  another: {
    TEST: 'this is my test value'
  }
};

当对象具有三层或更多层嵌套时,这不是最优雅的读物,但是它是一个选择:

const source: Indexed<Indexed<Indexed<Indexed<string>>>> = {};