如何根据并集/相交对象类型的值来创建类型?

问题描述 投票:1回答:1

我有一个硬类型,想出如何将类型定义为预定义对象类型中所有可能值的并集。

假设我们有一个自动生成的类型Person,看起来像这样:

type Person = {
  favouriteColor: string
  age: number
  female: boolean
}

[如何使用Person类型创建等于string | number | boolean的联合类型?

在我的用例中,类型为Person是自动生成的。我在对象上使用Ramda的map函数,将该函数应用于该对象的每个值:

import { map } from 'ramda'

classroom.people.forEach(person =>
  // Ramda’s `map` is applied to a `block` object here:
  map<Person, Person>(property => {
    // The type definitions for Ramda are not sufficiently strong to infer the type
    // of `property`, so it needs to be manually annotated.
    return someFunction(property)
  }, person)
)

我正在寻找的行为实质上与keyof等效,但据我所知TypeScript中没有valueof。等效的实现是什么样的?

非常感谢!


编辑:通常,解决方案将由@ kaya3建议:type ValueOf<T> = T[keyof T]。但是,仔细检查后,我的情况似乎受到以下困扰:

type PersonCommonFields = {
  age: number,
  name: string
}
type PersonFragment =
  | { favouriteColor: string }
  | { female: boolean }
  | { eyeColor: Color }
  | { born: Date }
type Person = PersonCommonFields & PersonFragment

在这种情况下,如上定义的ValueOf<Person>返回number | string,即仅返回PersonCommonFields中的值,而忽略PersonFragment。此示例的预期结果将是number | string | boolean | Color | Date

是否有其他方法可以解决这种情况?

很多(很多!)预先感谢!

typescript ramda.js
1个回答
0
投票

我注意到,如果您将|中的&更改为PersonFragment,则可以使用它(换句话说,创建单一类型而不是联合类型)。似乎您希望这些字段是可选的,是否可以将Partial与单一类型一起使用(与使每个字段可选一样的行为)?

type PersonCommonFields = {
  age: number,
  name: string
}
type PersonFragment = Partial<{
  favouriteColor: string,
  female: boolean,
  eyeColor: Color,
  born: Date
}>
type Person = PersonCommonFields & PersonFragment;

type PersonTypes = Person[keyof Person]; // number | string | boolean | Color | Date

编辑:

@@ kaya3在注释中指出,当前行为是应设置PersonFragment中的至少一个字段。如果这不是必需的,则上面的应该起作用。

假设条件实际上是仅存在1个字段,不能更多?您可以使用自定义类型XOR 1强制执行此操作,结果对象将允许您访问键。

// Note: Define these in your global typings file so they can be reused
type Without<T, U> = { [P in Exclude<keyof T, keyof U>]?: never };
type XOR<T, U> = T | U extends object ? (Without<T, U> & U) | (Without<U, T> & T) : T | U;

type PersonFragment = XOR<
  { favouriteColor: string },
  XOR<{ female: boolean }, XOR<{ eyeColor: Color }, { born: Date }>>
>;

1https://stackoverflow.com/a/53229857/522877

© www.soinside.com 2019 - 2024. All rights reserved.