I'm writing a converter that converts a tuple array into an object using a lookup object that tells the function which strings map to which properties. However, I can't find a way to tell typescript that it's an array of tuples with specific types, the resulting tuples are always unions. Here's how it looks like:
interface EndObj {
a: number;
b: string;
c?: number;
}
interface InitObj {
d: string;
e: string;
f: string;
}
const map = {
d: 'a',
e: 'b',
f: 'c'
} as const;
type MapType = typeof map;
type ResultTuple<T extends keyof InitObj> = [T, EndObj[MapType[T]]];
type ResultTupleArray = ResultTuple<keyof InitObj>[];
const resultObj: ResultTupleArray = [['d', 1], ['e', 3], ['f', 3]]; // invalid! the value of 'e' should only allow strings
I think the reason why typescript allows this is, because ResultTupleArray is defined with keyof InitObj, so the resulting tuple array generic is always the same, so T will always be the same instead of specific per array entry, thus it can only be described with a union.
Here's how I found it out:
const undetected: ResultTuple<keyof InitObj> = ['e', 4]; // should be invalid
const detected: ResultTuple<'e'> = ['e', 4]; // actually shows an error for 4 (Type 'number' is not assignable to type 'string'.)
For a bit of context, here's how the converter looks like:
function mapInitToEnd(resultO: ResultTupleArray) {
const endObj: EndObj = {
a: -1,
b: ''
};
for (const tuple of resultO) {
const [key, val] = tuple;
const mappedKey = map[key];
endObj[mappedKey] = val;
}
return endObj;
}
Is there a way to tell typescript that the generic is only valid per entry in the tuple array, and not for the full array?