const source = [
  { group: 'first', key: 'A' },
  { group: 'first', key: 'B' },
  { group: 'second', key: 'A' }
] as const;

type DerivedGroupKeys = `${typeof source[number]['group']}.${typeof source[number]['key']}`;
//gives "first.A" | "first.B" | "second.A" | "second.B"
type HardCodedGroupKeys = 'first.A' | 'first.B' | 'second.A';
//gives "first.A" | "first.B" | "second.A"

Chciałbym być taki sam jak HardCodedGroupKeys (bez hardcoding). Jestem tam prawie, ale daje mi każdą możliwą kombinację grupy i klucza, a nie tylko kombinacjami zdefiniowanymi w tablicy. czy to możliwe?

1
Keegan 82 10 luty 2021, 13:54

2 odpowiedzi

Najlepsza odpowiedź

Dokumenty Szablon dosłowne typy mówią, że:

Gdy unia jest używana w pozycji interpolowanej, typem jest zestaw każdego możliwego dosłownego ciągów, który może być reprezentowany przez każdego członka Unii:

Aby przezwyciężyć ten problem, możesz oddzielnie mapować każdy element tablicy, zamiast mapować Unię.

const source = [
  { group: 'first', key: 'A' },
  { group: 'first', key: 'B' },
  { group: 'second', key: 'A' }
] as const;

type ToLiteral<T> = 
  T extends {group: infer G, key: infer K} ? 
    G extends string ? 
      K extends string ? `${G}.${K}` : never 
    : never 
  : never;

type SourceElemsType = typeof source[number]
type SourceElesLiterals = ToLiteral<SourceElemsType>
2
Lesiak 10 luty 2021, 12:01

Oczekuje się tego zachowania, do Numeryczny dosłowne: Jeśli indeksujesz krotkę z dosłownym n, uzyskany typ może tylko być typem NTH członek krotki (stąd, bez związku).

Po pierwsze, możemy uzyskać związek wskaźników krotki:

type Indices<A> = Exclude<keyof A, keyof any[]>;

Następnie wystarczy utworzyć odwzorowany typ z krotki za pomocą "Klawisze" jako indeksów krotkowych i "wartości" jako pożądane wyjście. Wreszcie, po prostu indekuj odwzorowany typ za pomocą wskaźników krotek:

type DerivedGroupKeys = { [ I in Indices<typeof source> ] : `${typeof source[I]['group']}.${typeof source[I]['key']}` }[Indices<typeof source>];
2
Oleg Valter 10 luty 2021, 12:07