This challenge is about transforming a tuple into an object type, where each key-value pair in the object corresponds to an element in the tuple.
Given a tuple (an array with a fixed number of elements, where each element can have a different type), we need to create a type TupleToObject<T>
that represents an object derived from the tuple T
. Each key in the object should be a string representation of an element in the tuple, and the value should be the same as the key.
For example, given the following tuple:
const tuple = ['tesla', 'model 3', 'model X', 'model Y'] as const
The TupleToObject<typeof tuple>
type would be:
{
tesla: 'tesla';
'model 3': 'model 3';
'model X': 'model X';
'model Y': 'model Y';
}
The solution to this problem involves using a few advanced TypeScript features:
-
Mapped Types: Mapped types allow us to create new types based on the properties of an existing type. In this case, we'll create a new object type where the keys and values are derived from the elements of the tuple.
-
Generic Constraints: By constraining the generic type
T
toreadonly (PropertyKey)[]
, we ensure thatT
is a tuple where each element can be used as an object property key (i.e., a string, number, or symbol). -
Type Indexing: Using
T[number]
, we can access the type of the elements in the tupleT
.
The solution will look something like this:
type TupleToObject<T extends readonly PropertyKey[]> = {
[K in T[number]]: K
}
Here, [K in T[number]]: K;
is the mapped type. It iterates over each element in the tuple T
and creates a property in the resulting object type where the key and value are the same as the tuple element.
PropertyKey
is a built-in TypeScript type that is a union type of these three types:
type PropertyKey = string | number | symbol
In the case of arrays and tuples, which are indexable by numbers, T[number]
means "the type of elements in the array or tuple T
".
[K in T[number]]: K
can be read as "for each type K
in the union of element types of T
, create a property with key of type K
and value of type K
".
The as const
assertion in TypeScript is used to signal that an object, array, or tuple should be treated as "read-only" and have its literal values preserved in the type system, This is often useful when working with complex type manipulations or enforcing immutability constraints.
For example, ...
const tupleMix = [1, '2', 3, '4'] as const
... should be treated as an immutable tuple with the specific literal values 1
, '2'
, 3
, and '4'
.
Without the as const
assertion, TypeScript would infer the type of tupleMix
as (number | string)[]
, which would lose the specific order and values of the elements in the tuple.