Reputation: 1476
Lets say I have a following interface that represents some filter settings:
interface IFilterSettings {
title: string,
teamMembers: Members
}
However, my filter can emit change for a single field only. How can I achieve deriving following type from IFilterSettings
?:
type FilterChange = {field: 'title', payload: string} | { field: 'teamMembers', payload: Members };
Upvotes: 0
Views: 431
Reputation: 2050
The core feature you need to use is Distributive Conditional Types. It allows to construct new union type from another union type.
interface Members {
someField: unknown
}
interface IFilterSettings {
title: string,
teamMembers: Members
}
// `Key extends any` is always true, but we need it to enable distributive conditional type
type FilterOption<Key extends keyof Value, Value> = Key extends any
// here we convert key to desired format
? { field: Key, payload: Value[Key] }
: never;
// If we try to use this variant, we end up with
// type FilterChange = { field: "title" | "teamMembers", payload: string | Members }
/*
type FilterOption<Key extends keyof Value, Value> = { field: Key, payload: Value[Key] }
*/
// Here we use `keyof Settings` to create initial union of all keys
type FilterChangeFromSettings<Settings> = FilterOption<keyof Settings, Settings>
type FilterChange = FilterChangeFromSettings<IFilterSettings>;
Upvotes: 1