jmeinlschmidt
jmeinlschmidt

Reputation: 1476

TypeScript map interface to literal type

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

Answers (1)

The core feature you need to use is Distributive Conditional Types. It allows to construct new union type from another union type.

playground

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

Related Questions