首页 > 解决方案 > 如何从联合/交集对象类型的值中创建类型?

问题描述

我有一个很难确定如何将类型定义为预定义对象类型中所有可能值的联合的类型。

假设我们有一个自动生成的类型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- 但据我所知valueof,TypeScript 中没有。等效的实现会是什么样子?

非常感谢你!


编辑:通常情况下,解决方案将按照@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.

是否有替代方法来解决这种情况?

很多(很多!)提前谢谢!

标签: typescriptramda.js

解决方案


我注意到,如果您将其更改|&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 个字段,而不是更多?您可以使用自定义类型XOR1来强制执行此操作,生成的对象将允许您访问密钥。

// 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


推荐阅读