Let say I want to write a function that takes as a parameter a two elements tuple.
The first element of the tuple is a tuple of strings, the second a tuple containing the same strings, but capitalized. The function then just returns this tuple.
I want my function to typecheck the parameters and the output.
So:
capitalizeTuple([["foo"], ["Bar"]]);
Should raise an error, because ["Bar"] is not the capitalized version of ["foo"]
And :
capitalizedTuple([["foo", "bar"], ["Foo","Bar"]]);
Should be okay, and the output infered as [["foo", "bar"], ["Foo", "Bar"]]
I first define :
type CapitalizeTuple<T extends string[]> = [
T,
{ [I in keyof T]: Capitalize<T[I]> }
];
Then, the naive approach is to do :
declare const capitalizeTuple: <T extends CapitalizeTuple<string[]>>(t: T) => T;
capitalizeTuple([["foo"], ["Bar"]]);
Typescript does not complain and the infered type is : [string[], "Bar"[]]
(the first tuple is NOT inferred as a tuple but as a string array)
My workaround to solve this problem is:
1/ Using the generic parameter T just for the inference of the first tuple
2/ Injecting [...T] (T alone won't be inferred as a tuple) into the generic type (CapitalizeTuple here)
3/ Using a second generic parameter U, to infer the actual type of the parameter t, and using it to infer the return type
declare const fixedCapitalizeTuple: <T extends string[], U>(
t: CapitalizeTuple<[...T]> & U
) => U;
fixedCapitalizeTuple([
["foo", "bar"],
["Foo", "Bar"],
]); // infered as [["foo", "bar"], ["Foo", "Bar"]] as expected
Is there any way to achieve my goal using only one type parameter, for instance T ?