Как вывести тип карты, ограничивая значения известным набором? - PullRequest
0 голосов
/ 06 февраля 2020

Я пытаюсь создать карту из набора строковых ключей для набора специфицированных c строк:

type Datum = { LOCATION: string, GENDER: number }

export const fieldKeys: Record<strings, keyof Datum> = {
  country: "LOCATION",
  gender: "GENDER"
};

, чтобы позже я мог индексировать объект типа Datum через один из ключей поля:

const d: Datum = { /* … */ }
const country = d[fieldKeys.country]

Однако, поскольку ключи записи fieldKeys являются произвольными строками, а не общеизвестным набором свойств, допускается неправильное использование:

// Passes type checker but is a bug.
const bug = d[fieldKeys.doesNotExist]

Кроме того, предполагаемый тип свойства при доступе через fieldKeys является типом объединения всех возможных значений свойства Datum:

// Inferred type is 'string | number' instead of string.
const shouldBeString = d[fieldKeys.country] 

В идеале TypeScript должен определять ключи записи, но код, подобный этому, не является разрешено, поскольку это рекурсивно:

export const fieldKeys: Record<keyof (typeof fieldKeys), keyof Datum> = {
  country: "LOCATION",
  gender: "GENDER"
};

Я могу обойти это с помощью стандартного кода, как это, но это не очень хорошее решение:

const keyOf = <D, K extends keyof D>(k: K): K => k

export const fieldKeys = {
  country: keyOf<Datum, "LOCATION">("LOCATION"),
  gender: keyOf<Datum, "GENDER">("GENDER")
} as const;

В целом, я хотел бы следующие, чтобы пройти проверку типа:

type Datum = { LOCATION: string, GENDER: number }

export const fieldKeys = {
  country: "LOCATION",
  gender: "GENDER",

  // Requirement: Type checker complains that NODATUMPROPERTY is is not a property of Datum.
  noDatumProperty: "NODATUMPROPERTY"
};

const d: Datum = { LOCATION: "Germany", GENDER: 1 }

// Requirement: inferred type is 'string'
const country = d[fieldKeys.country]

// Requirement: Type checker complains about non-existing property in fieldKeys.
const bug1 = d[fieldKeys.doesNotExist]

У кого-нибудь есть идеи, как это сделать?

...