I'm trying to wrap my head around a problem concerning mapped tuple types. They appear to work when I explicitly define a type to map, but when the type to map is inferred via a generic, the type-system appears to not work correctly.
class Boxed<T> {
constructor(private arg: T){ }
}
type MapToRaw<T> = { [K in keyof T]: T[K] extends Boxed<infer E> ? E : never };
// WORKS AS EXPECTED
let val: MapToRaw<[Boxed<number>, Boxed<string>]>;
// 'val' is of type [number, string]
// DOESN'T WORK AS EXPECTED
let fn = <X extends Boxed<any>[]>(arg: X) => null as any as MapToRaw<X>;
let res = fn([new Boxed(0), new Boxed('')]);
// 'res' is of type (string | number)[]
I actually don't think there is a way to do this without doing the following:
let fn = <X extends Boxed<any>[]>(...arg: X) => null as any as MapToRaw<X>;
let res = fn(new Boxed(0), new Boxed(''));
// 'res ' is of type [number, string]
but in my case, I'd prefer to pass in an array rather than variadic arguments
You need to hint to the compiler that B
should be a tuple, not just a simple array. You can do this with a type constraint of [T] | T[]
:
class Boxed<T> {
constructor(private arg: T){ }
}
type MapToRaw<T> = { [K in keyof T]: T[K] extends Boxed<infer E> ? E : never };
let fn = <X extends [Boxed<any>] | Boxed<any>[]>(arg: X) => null! as MapToRaw<X>;
let res = fn([new Boxed(0), new Boxed('')]);