Tuple to Object in TypeScript via generics
Asked Answered
H

2

7

I'm attempting to transform a Tuple union in TypeScript to an object, without losing any types.

Here is an example of how it would work:

type Tuples = ["foo", string] | ["bar", boolean] | ["baz", null];

/*
ideally the type would be:
{
  foo: string;
  bar: boolean;
  baz: null;
}
*/
type AsObject = DoSomething<Tuples>;

A simple solution to the above would be:

type TupleToObject<T extends [string, any]> = { [key in T[0]]: T[1] };

/*
type is:
{
    foo: string | boolean | null;
    bar: string | boolean | null;
    baz: string | boolean | null;
}
*/
type TypesLost = TupleToObject<Tuples>;

However we lose some type information as all values are pulled together in one union type.

I'm looking for a solution using generics that does not lose this type information, and would appreciate any deeper insight into mapping generic tuples in TypeScript.

Heinrick answered 11/7, 2019 at 12:16 Comment(0)
W
15

You can get the desired effect, by using Extract. The basic idea is we will extract from T the appropriate type from the union that corresponds to the common key:

type Tuples = ["foo", string] | ["bar", boolean] | ["baz", null];
type TupleToObject<T extends [string, any]> = { [key in T[0]]: Extract<T, [key, any]>[1] };

/*
type is:
{
    foo: string;
    bar: boolean;
    baz: null;
}
*/
type TypesLost = TupleToObject<Tuples>;
Wampler answered 11/7, 2019 at 12:21 Comment(1)
Perfect! Thanks for solving my headache. Extract was exactly what I was blanking on.Heinrick
D
3

I wanted to find a simplified solution that does not involve using a utility type.

Came up with this:

const tuple = [123, '321', 789, '987'] as const

type TupleToObject<T extends readonly any[]> = { [Key in T[number]]: Key }
Doctor answered 16/2, 2023 at 16:17 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.