Home > Mobile >  Typescript Pick optionnal unset variable
Typescript Pick optionnal unset variable

Time:03-24

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
  • 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.

Playground

  • Related