Given a type defined by nested types all containing a key label
type Payloads = {
EventA: { label: 'Foo', content: object }
EventB: { label: 'Bar', content: object }
EventC: { label: 'Baz', content: object }
}
And a type defined as the union of select potential label
types
type SelectLabels = 'Foo' | 'Bar'
How can I create a type defined as only the keys of Payloads
whose value type has a label
key whose value type is a member of SelectLabels
, resulting in the following behavior:
function f(x: TypeGoesHere) {}
f('EventA') // OK
f('EventB') // OK
f('EventC') // Error
I've tried the following
type TypeGoesHere = Pick<keyof Payloads, Payloads[keyof Payloads]['label'][SelectLabels]>
but get the following error:
Property 'Bar' does not exist on type '"Foo" | "Bar" | "Baz"'.ts(2339)
Property 'Foo' does not exist on type '"Foo" | "Bar" | "Baz"'.ts(2339)
type Payloads = {
EventA: { label: 'Foo', content: object }
EventB: { label: 'Bar', content: object }
EventC: { label: 'Baz', content: object }
}
type SelectLabels = 'Foo' | 'Bar'
// similar to Object.entries
type Entries<T> = { [K in keyof T]: [key: K, value: T[K]] }[keyof T]
type TypeGoesHere = Extract<Entries<Payloads>, [any, { label: SelectLabels }]>[0]
// ^?
// type TypeGoesHere = "EventA" | "EventB"
type Explain1 = Entries<Payloads>
// ^?
// ['EventA', {label: 'Foo, ...}] | ['EventB', { label: 'Bar', ...}] | ['EventC', { label: 'Baz', ...}]
// same as Object.entries for runtime
type Explain2 = Extract<Entries<Payloads>, [any, { label: SelectLabels }]>
// ^?
// ["EventA", { label: 'Foo', ... }] | ["EventB", { label: 'Bar', ... }]
// pick tuples where value (second item) matches { label: SelectLabels }
type Explain3 = Explain2[0]
// ^?
// "EventA" | "EventB"
// take first element of every tuple