Home > database >  Merge fields of variadic tuple in TypeScript
Merge fields of variadic tuple in TypeScript

Time:07-19

I have a collection of objects with similar structure:

const a = { x : true }
const b = { x : 5 }
const c = { x : `text` }

Every objects has an x field, but its type may be different. All these objects are passed into a function f as a template tuple:

function f<
    T extends { x : unknown[] }
>(
    ...t : [...{ [i in keyof T] : T[i] }]
) {
    // return t[random index].x 
}

f(a, b, c)

The function f has to return one of these x fields, but I can't figure out how to properly specify the return type for it. For instance, in this particular case the type should be true | 5 | "text".

I have tried to put T[keyof T]["x"] as a result but got an error Type "x" cannot be used to index type 'T[keyof T]'. How this should be done properly?

CodePudding user response:

If you want the return type to be true | 5 | "text" you will have to use as const to preserve the narrowed type information.

const a = { x : true } as const
const b = { x : 5 } as const
const c = { x : `text` } as const

For the function f, you can use T to store a tuple of the types of the x properties.

function f<
    T extends any[]
>(...t : [...{ [I in keyof T] : { x: T[I] } }]): T[number] {
    return t[0]!.x 
}

The return type would be T[number].

You now have the correct return type.

const result = f(a, b, c)
//    ^? const result: true | 5 | "text"

Playground


Here is a slightly refactored version.

function f<
    T extends { x: any }[]
>(...t: [...T]): T[number]["x"] {
    return t[0]!.x 
}

Also another version which also correctly handles object literals.

type Narrowable = string | number | boolean | symbol | object | undefined | void | null | {};
function f<
    T extends { x: S }[], S extends Narrowable
>(...t: [...T]): T[number]["x"] {
    return t[0]!.x 
}

const result = f({ x : true }, { x : 5 }, { x : `text` })
  • Related