TypeScript - 从另一个联合类型的字段值获取联合类型

3
在Typescript中,是否可以从另一个联合类型的字段值获取联合类型?
type MyUnionType = 
  | { foo: 'a', bar: 1 }
  | { foo: 'b', bar: 2 } 
  | { foo: 'c', bar: 3 }

// can I generate this automatically? 
// i.e. a union of the possible values of foo in MyUnionType?
type Foos = 'a' | 'b' | 'c'

我曾希望Pick<MyUnionType, 'foo'>可以做到,但它并不能完全满足需求——它返回了我想要的类型,但是嵌套在一个名为foo的字段下:{ foo: 'a' | 'b' | 'c' }

3个回答

4

type Foos = MyUnionType['foo'] 只要每个类型都有 foo 字段,就能正常使用。 测试

type MyUnionType = 
  | { foo: 'a', bar: 1 }
  | { foo: 'b', bar: 2 } 
  | { foo: 'c', bar: 3 }

type FooType = MyUnionType['foo']
// FooType = "a" | "b" | "c"

如果您需要在异构联合类型上进行分发,则可以使用字段过滤掉这些联合类型中的类型。请参考分布式条件类型
type PickField<T, K extends string> = T extends Record<K, any> ? T[K] : never;

你接着可以使用

type MyUnionType = 
  | { foo: 'a', bar: 1 }
  | { foo: 'b', bar: 2 } 
  | { foo: 'c', bar: 3 }
  | { bar: 4 }

type FooType = MyUnionType['foo']
// Property 'foo' does not exist on type 'MyUnionType'. :-(

type FooType2 = PickField<MyUnionType, 'foo'>
// type FooType2 = "a" | "b" | "c"

type PickField<T, K extends string> = T extends Record<K, any> ? T[K] : never;
// Alternatively, you could return `undefined` instead of `never`
// in the false branch to capture the potentially missing data

0
要获取所有可能的数据集合,例如来自对象字面类型,请使用以下方法:
type Intersect<T> =
    (T extends any ? (x: T) => any : never) extends
    (x: infer R) => any ? R : never
type ValueIntersectionByKeyUnion<T, TKey extends keyof Intersect<T> = keyof Intersect<T>> = T extends Record<TKey, any> ? ({
    [P in TKey]: T extends Record<P, any> ? (k: T[P]) => void : never
}[TKey] extends ((k: infer I) => void) ? I : never) : never;
type Usage = { [K in keyof Intersect<TA1>]: ValueIntersectionByKeyUnion<TA1, K> };

0

Sean Vieira 所拥有的东西非常棒。这里还有另一种方式,虽然略微冗长:

const ALL_TYPES =[
   { foo: 'a', bar: 1 },
   { foo: 'b', bar: 2 },
   { foo: 'c', bar: 3 }] as const

const ALL_FOOS = [...ALL_TYPES.map(t => t.foo)] as const;

type MyUnionType = typeof ALL_TYPES;
type FooType = typeof ALL_FOOS;
// FooType = "a" | "b" | "c"

所以这是一种有趣的方法,但不适合我的用例,因为我不想在运行时组装foos数组来获取类型。如果你无论如何都需要那个数组,那么这可能更有意义。 - davnicwil
1
@davnicwil 我完全理解 ;) 虽然这样做仍然有意义,但发布它可能还有其他用例(例如,具有许多属性的大型对象数组,并选择仅转换为类型的少数属性)。 干杯! - Evaldas Buinauskas

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接