具有定义值的 Typescript 动态对象键

标签 typescript typescript-typings typescript-generics

我遇到了一个问题,试图让 typescript 为我识别 javascript 对象的键,同时强制每个键的值类型,因为我想创建对象键的类型,所以我不能只创建一个常规 type MyObject = { [key: string]: <insert type> } .

想象一个物体 myobject我在其中提取它的键,例如:

const myobject = {
  foo: {},
  bar: {}
};

type MyObjectKeys = keyof typeof myobject; // 'foo' | 'bar'

如何向键的值添加类型定义,同时仍然能够提取/继承键的定义?如果我做这样的事情,那么我将不再能够提取对象的确切键,而只能提取类型(字符串):

type MyObject = { [key: string]: { value: boolean }}
const myobject = {
  foo: { value: true },
  bar: { value: false }
};

type MyObjectKeys = keyof typeof myobject; // string

我想我可以通过创建一个辅助函数来实现这一点,例如:

function enforceObjectType<T extends MyObject>(o: T) {
    return Object.freeze(o);
}
const myobject = enforceObjectType({
  foo: {},
  bar: {}
});

但是我更愿意为它定义一个明确的类型,而不必污染代码,只编写与类型相关的函数。有没有办法允许一组字符串作为一个类型的键而不重复?

这样做的目的是让 TypeScript 帮助指出正确的对象键,例如(实际用法有点复杂,所以我希望这能很好地描述它):

type MyObjectKeys = keyof typeof myobject; // string
function getMyObjectValue(key: MyObjectKeys) {
   const objectValue = myobject[key];
}

// suggest all available keys, while showing an error for unknown keys
getMyObjectValue('foo'); // success
getMyObjectValue('bar'); // success 
getMyObjectValue('unknown'); // failure

收尾:我想将一个对象定义为 const (实际上是 Object.freeze )并且能够:
  • 提取对象的确切键(无需键入每个键的定义)。
  • 定义每个键的类型,不要将键覆盖到 string而不是它们是什么 - 比如 'foo' | 'bar' .

  • 完整示例

    type GameObj = { skillLevel: EnumOfSkillLevels }; // ADD to each key.
    const GAMES_OBJECT = Object.freeze({
       wow: { skillLevel: 'average' },
       csgo: { skillLevel 'good' }
    )};
    
    type GamesObjectKeys = keyof typeof GAMES_OBJECT;
    
    function getSkillLevel(key: GamesObjectKeys) {
      return GAMES_OBJECT[key]
    }
    
    getSkillLevel('wow') // Get the actual wow object
    getSkillLevel('unknown') // Get an error because the object does not contain this.
    

    根据上述,我不能执行以下操作,因为这会将已知键覆盖为任何字符串:

    type GameObj = { [key: string]: skillLevel: EnumOfSkillLevels };
    const GAMES_OBJECT: GameObj = Object.freeze({
       wow: { skillLevel: 'average' },
       csgo: { skillLevel 'good' }
    )};
    
    type GamesObjectKeys = keyof typeof GAMES_OBJECT;
    
    function getSkillLevel(key: GamesObjectKeys) {
      return GAMES_OBJECT[key]
    }
    
    getSkillLevel('wow') // Does return wow object, but gives me no real-time TS help
    getSkillLevel('unknown') // Does not give me a TS error
    

    另一个例子:见this gist例如并将其复制到 typescript playground如果你想改变代码

    最佳答案

    希望这对你现在有帮助:

    enum EnumOfSkillLevels {
      Average = 'average',
      Good = 'good'
    }
    
    type GameObject<T extends { [key: string]: {skillLevel: EnumOfSkillLevels} }> = {
      [key in keyof T ]: {skillLevel: EnumOfSkillLevels}
    }
    const GAMES_OBJECT = {
       wow: { skillLevel: EnumOfSkillLevels.Average },
      csgo: { skillLevel: EnumOfSkillLevels.Good },
       lol: { skillLevel: EnumOfSkillLevels.Good }
    } as const;
    
    
    function getSkillLevel(key: keyof GameObject<typeof GAMES_OBJECT>) {
      return GAMES_OBJECT[key]
    }
    
    getSkillLevel('wow') // Does return wow object, but gives me no real-time TS help
    getSkillLevel('lol') // Does return wow object, but gives me no real-time TS help
    getSkillLevel('unknown') // Does give me a TS error
    

    游乐场link .

    关于具有定义值的 Typescript 动态对象键,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/61013605/

    相关文章:

    typescript : Generic type "extract keys with value of type X" does not behave as expected

    typescript - Typescript 对象索引器中的泛型

    javascript - 以 Angular 本地获取网址

    typescript - Typescript 请求/响应的条件类型

    函数类型和参数类型映射之间的 typescript 匹配

    typescript - 如何输入以接口(interface)作为参数的方法

    javascript - typescript 将类型添加到库方法参数

    node.js - 对公共(public)类使用共享 Node 模块

    angular - Angular 6 中 ngIf 的多个条件

    Typescript 告诉我属性 'padStart' 在类型 'string' 上不存在。为什么?