Follow

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use
Contact

Merge fields of variadic tuple in TypeScript

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

MEDevel.com: Open-source for Healthcare and Education

Collecting and validating open-source software for healthcare, education, enterprise, development, medical imaging, medical records, and digital pathology.

Visit Medevel

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?

>Solution :

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` })
Add a comment

Leave a Reply

Keep Up to Date with the Most Important News

By pressing the Subscribe button, you confirm that you have read and are agreeing to our Privacy Policy and Terms of Use

Discover more from Dev solutions

Subscribe now to keep reading and get access to the full archive.

Continue reading