Typescript extract keys from an object where each key value has a specific property

huangapple go评论62阅读模式
英文:

Typescript extract keys from an object where each key value has a specific property

问题

type GeneratedStatKeys = {
  [I in keyof typeof STATS]: typeof STATS[I]['generated'] extends undefined ? never : I;
}; // "minpg" | "avgrec"
英文:

I have a read-only object that is used to represent the stats for my game like so:

const STATS = {
  gp: {
    name: "Games Played",
    slug: "GP",
  },
  minp: {
    name: "Minutes Played",
    slug: "MINP",
  },
  minpg: {
    name: "Average Minutes Per Game",
    slug: "MINPG",
    generated: {
      // ...properties,
    },
  },
  avgrec: {
    name: "Average Receptions",
    slug: "avgrec",
    generated: {
      // ...properties,
    },
  },
} as const;

I want to extract all the keys from the object that have a generated property set. That way I can use this key in some of my utility functions. Thus, I tried the below:

type GeneratedStatKeys = {
  [I in keyof typeof STATS]: typeof STATS[I]["generated"] extends undefined
    ? never
    : typeof STATS[I];
}; // "minpg" | "avgrec"

GeneratedStatKeys should be a union type of strings, the extracted keys of STATS. However, Typescript is throwing an error "Type '"generated"' cannot be used to index type STATS"

This makes sense, so I annotated the STATS object to be:

const STATS: Record<string, Stat> = {
//...stats
} as const;

where Stat is:

interface Stat {
  name: string;
  slug: string;
  generated?: {
  //...props
  };
}

This works, however, GeneratedStatKeys type is then string.

What is the workaround? I could just manually create a string union type for the generated keys but was wondering if this could be "automated".

答案1

得分: 2

无法使用类型的键索引,除非它是类型的已知键。由于typeof STATS的某些属性没有generated键,因此无法以这种方式对任意属性进行索引。相反,您可以使用keyof运算符检查属性是否具有该键:

type GeneratedStatKeys = {
  [K in keyof typeof STATS]: "generated" extends keyof typeof STATS[K] ? K : never
}[keyof typeof STATS]
// type GeneratedStatKeys = "avgrec" | "minpg"

一旦进行了这个检查,您就可以进行索引访问(例如,"generated" extends keyof Foo ? Foo[K] : ...),但在您的情况下,您只需要键,而不是属性类型。

英文:

You can't index into a type with a key unless it's a known key of the type. Since some of the properties of typeof STATS don't have a generated key, you can't index into an arbitrary property that way. Instead you could check if the property has that key by using the keyof operator:

type GeneratedStatKeys = {
  [K in keyof typeof STATS]: "generated" extends keyof typeof STATS[K] ? K : never
}[keyof typeof STATS]
// type GeneratedStatKeys = "avgrec" | "minpg"

Once you did this check you could do the indexed access (e.g., "generated" extends keyof Foo ? Foo[K] : ...) but in your case you just want the key, not the property type.

Playground link to code

huangapple
  • 本文由 发表于 2023年2月7日 02:43:01
  • 转载请务必保留本文链接:https://go.coder-hub.com/75365371.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定