To start, define a type for your source data:
type Data = Record<string, {
values: readonly string[],
multiple?: boolean
}>
Next, create a conditional type that is mapped to accept the defined type:
type Fields<T extends Data> = {
[K in keyof T]:
T[K]['multiple'] extends true
? T[K]['values'][number][]
: T[K]['values'][number]
}
This conditional type iterates over all keys in T
(such as field1
and field2
) and determines the value type of each property based on a condition.
The condition states that if T[K]['multiple'] extends true
, then return an array containing the specified member types from the values
property, otherwise return a non-array of that type.
You can now utilize this type as follows:
function someFunction<T extends Data>(data: T): Fields<T> {
// TODO: implement this
}
This function works as expected:
const fields = someFunction({
field1: { values: ['a', 'b', 'c'] },
field2: { values: ['c', 'd', 'e'], multiple: true }
} as const)
fields.field1 // ('a' | 'b' | 'c')[]
fields.field2 // 'a' | 'b' | 'c'
Explore Playground Here