I'm trying to use the "pick" function of typescript to get all the possible values of my objects. My objects have optional attributes so they are not necessarily set
const foo = [
{
name: 'index',
},
{
name: 'id',
type: 'number',
},
{
name: 'error',
},
] as const
type ElementArg<T extends ReadonlyArray<unknown>> = T extends ReadonlyArray<infer ElementType>
? Pick<ElementType, 'name' | 'type'>
: never
type result = ElementArg<typeof foo>
//result : {name: "index" | "id" | "error"}
//expected : {name: "index" | "id" | "error" type: "number" | "undefined"}
and I also try to convert "type" attribut to a type with :
type typeDecoder<T> = T extends 'number' ? number
: T extends 'number[]' ? number[]
: T extends 'string' ? string
: T extends 'string[]' ? string[]
: T extends 'boolean' ? boolean
: T extends 'undefined' ? undefined
: never;
but I think there is a better way to do it and I don't know where to use my function
CodePudding user response:
I managed to get something to work:
type ElementArg<T extends ReadonlyArray<unknown>, R extends {} = {}> = T extends readonly [infer First, ...infer Rest]
? ElementArg<Rest, {
[K in keyof First | keyof R]:
K extends keyof R
? K extends keyof First
? R[K] | First[K]
: R[K] | "undefined"
: K extends keyof First
? First[K]
: never
}>
: R;
The main idea is that we loop through each of the elements in the tuple and then we add to the result we accumulate.
T extends readonly [infer First, ...infer Rest]
Here we get the first element and the rest as a tuple. Next is this big chunk:
ElementArg<Rest, {
[K in keyof First | keyof R]:
K extends keyof R
? K extends keyof First
? R[K] | First[K]
: R[K] | "undefined"
: K extends keyof First
? First[K]
: never
}>
We use ElementArg
again on the remaining elements, and then the long complicated mapped type correctly adds this element's contents to the results.
The logic is like this:
For each key in the element or result
If the key is a key of the result
If the key is a key of the element
- Add the key's value to the result
Otherwise
- Add
"undefined"
to the result
- Add
Or else if the key is a key of the element
- This is a new key we add to the result
And finally if the first step where we attempt to get the first element does not work, that means T
is empty and we are done, so we return R
.