const obj = { wheels: 4, lights: 2, doors: 4 }
someMapFunction(obj, {
props: ["wheel", "lights"],
format: (wheels, lights) => `${wheels}-${lights}`
})
How would I type someMapFunction
so that typescript knows that props
can only be keys of obj
and that the format
function will take all of the values that the props
array values point to within obj
?
CodePudding user response:
You would define the function like this:
function someMapFunction<
T,
K extends (keyof T)[]
>(obj: T, propsAndFormat: {
props: [...K],
format: (...args: {
[I in keyof K]: T[K[I]]
}) => string
}) {
return null!
}
It has two generic parameters T
and K
. T
describes the type of the object passed as obj
while K
is a tuple of keys of T
. When we declare the parameter type of props
, we use the variadic tuple syntax [...K]
to infer K
as a tuple and not and array since the order is important.
For format
, we declare it to be a rest parameter where the order and type of elements are described by a tuple. To create this tuple, we can map over the elements I
in the tuple K
and use them to extract the corresponding type of T
.
CodePudding user response:
Tobias' answer is right, I would just do it somewhat differently. I would make the type T
extend a Record
since you are dealing with objects. And I don't think you need to use a tuple.
type PropsAndFormat<T> = {
props: keyof T;
format: (...keys: string[]) => string;
};
function someMapFunction<T extends Record<string, unknown>>(
obj: T,
{ props, format }: PropsAndFormat<T>,
): string {
//
}