首页 > 解决方案 > 如何在将值限制为已知集合的同时推断地图的类型?

问题描述

我正在尝试创建从一组字符串键到一组特定字符串的映射:

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]

有谁知道如何做到这一点?

标签: typescripttype-inference

解决方案


推荐阅读