在 TypeScript 中获取数组子集的类型

Getting the Type of a Subset of an Array in TypeScript

我有一个数据结构(它可以是一个数组或一个对象)来保存一些设置数据。目前看起来像这样:

const settings = [
  {name: 'Albert', value: 'a', isDefault: true}, 
  {name: 'Bradley', value: 'b'}
] as const

以及

的类型
type TAllValues = settings[number]['value']  // is 'a' | 'b' <-- that Union Type is what I want

我希望做的是能够根据设置中的匹配条件过滤此列表以获得子集。像这样

type TDefaultValues = FilterSettings<settings, {isDefault: true}> // would be just 'a'

我可以传入具有此形状的 typecondition 并为符合条件的条目获取值的联合类型。

如果有帮助,我也可以将数据结构更改为对象:

const settings = {
  a: {name: 'Albert', isDefault: true}, 
  b: {name: 'Bradley'}
}

编辑 注意 - WebStorm 存在一个问题,它以不同方式对待某些联合。我还没有发现为什么会这样,但是 BarkersBarkers2 在我尝试过的所有其他环境中都是一样的。在 Webstorm 中,从“as const”对对象的子集使用扩展是错误的,在其他任何地方都是正确的。

const Animals = [
  { animal: 'cat', bark: false },
  { animal: 'dog', bark: true }
] as const

type TAnimals = typeof Animals[number]
type TAnimals2 = { animal: 'cat'; bark: false } | { animal: 'dog'; bark: true }

type Barkers = Extract<TAnimals, { bark: true }>  // <--- never
type Barkers2 = Extract<TAnimals2, { bark: true }>  // <--- correct

您可以使用 distributive conditional type 检查设置是否符合条件,select 仅检查符合条件的设置:

const settings = [
  { name: 'Albert', value: 'a', isDefault: true },
  { name: 'Bradley', value: 'b' }
] as const

type Setting = typeof settings[number]

type FilterSettings<Condition, S extends Setting = Setting> = 
  S extends Condition ? S["value"] : never

type TDefaultValues = FilterSettings<{ isDefault: true }> // "a"

Playground