Website-Suche

Typescript extrahiert Schlüssel aus einem Objekt, bei dem jeder Schlüsselwert eine bestimmte Eigenschaft hat


Ich habe ein schreibgeschütztes Objekt, das verwendet wird, um die Statistiken für mein Spiel wie folgt darzustellen:

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;

Ich möchte alle Schlüssel aus dem Objekt extrahieren, die eine generierte Eigenschaft gesetzt haben. Auf diese Weise kann ich diesen Schlüssel in einigen meiner Hilfsfunktionen verwenden. Daher habe ich Folgendes ausprobiert:

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

GeneratedStatKeys sollte ein Union-Typ von Strings sein, die extrahierten Schlüssel von STATS. Typescript wirft jedoch einen Fehler: „Type 'generated' kann nicht verwendet werden, um den Typ STATS zu indizieren“

Das ergibt Sinn, also habe ich das STATS-Objekt wie folgt annotiert:

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

wo Stat ist:

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

Dies funktioniert, jedoch ist der Typ von GeneratedStatKeys dann string.

Was ist die Lösung? Ich könnte einfach manuell einen String-Union-Typ für die generierten Schlüssel erstellen, habe mich aber gefragt, ob dies "automatisiert" werden könnte.

Antwort #1

Sie können nicht mit einem Schlüssel in einen Typ indexieren, es sei denn, es handelt sich um einen bekannten Schlüssel des Typs. Da einige der Eigenschaften von typeof STATS keinen generated-Schlüssel haben, können Sie nicht auf eine beliebige Eigenschaft auf diese Weise zugreifen. Stattdessen könnten Sie überprüfen, ob die Eigenschaft diesen Schlüssel hat, indem Sie den keyof-Operator verwenden:

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

Sobald Sie diese Überprüfung durchgeführt haben, könnten Sie den indexierten Zugriff ausführen (z. B. "generated" extends keyof Foo ? Foo[K] : ...), aber in Ihrem Fall wollen Sie nur den Schlüssel, nicht den Eigenschaftstyp.

Playground-Link zum Code

Verwandte Artikel