I have some union, generic class, and generic function
type SomeUnion = "first" | "second" | "third"
class SomeClass<TypeFromUnion extends SomeUnion>{}
function someFn<A extends SomeUnion, B extends SomeUnion>(a: SomeClass<A>, b:SomeClass<B>) {}
For call
someFn(new SomeClass<"first">(), new SomeClass<"second">())
inside the function, a
processes as SomeClass<"first">
, b
as SomeClass<"second">
. Exactly the types I need.
But I need the function to be with rest parameters. Something like:
function someFn<T extends SomeUnion>(...rest: SomeClass<T>[]) {}
With the same function call, now rest[0]
processes as SomeClass<"first" | "second">
. I understand why this happens, but I need the type of rest[0]
to be processed as SomeClass<"first">
, rest[1]
as SomeClass<"second">
and so on. Otherwise it breaks my next type inference. How can I achieve what I need?
The calls are expected to be like:
someFn(new SomeClass<"first">())
someFn(new SomeClass<"third">(), new SomeClass<"second">())
someFn(new SomeClass<"third">(), new SomeClass<"first">(), new SomeClass<"second">())
CodePudding user response:
I think you need a tuple, not an array type, to separate each element of the rest generic type.
Then you could use a mapped tuple type
to map each one to the corresponding SomeClass
type SomeUnion = "first" | "second" | "third"
class SomeClass<TypeFromUnion extends SomeUnion>{}
function someFn<T extends [...SomeUnion[]]>(...rest: {[K in keyof T]: SomeClass<T[K]>}): typeof rest {
return rest;
}
let vs = someFn(new SomeClass<"first">(), new SomeClass<"second">(), new SomeClass<"third">())
// ^?let vs: [SomeClass<"first">, SomeClass<"second">, SomeClass<"third">]