I am trying to write typings for a function that is supposed to take an object and some of its keys as arguments and returns a new object where the value of specified keys can be the original or a Set/Array of original value type.
For example : If we were to pass an object of the following type :
interface Example {
a: number
b: number
c: string
}
and pass a and c as the keys, then the returned type would be
{
a: number | Set<number> | number[]
b: number
c: string | Set<string> | string[]
}
I have manages to do this by defining the following types
type SetOrArray<T, K extends (keyof T)[]> = { [V in K[number]]: Set<T[V]> | T[V][] }
type UnionType<T, K extends (keyof T)[]> = T | SetOrArray<T, K>
But when I try this with an object, then only the keys passed (in K) are preserved in the resulting UnionType and the remaining keys, which should have just been present with their original types due to T | union, are not existing on the UnionType.
For example:
function afunc<T, K extends (keyof T)[])>(obj: T, ...keys: K): UnionType<T, K> {
return obj // just for example
}
const obj = {a: 1, b: 2, c: "apple"}
const res = afunc(obj, "a", "c")
// res.a exists with type number | Set<number> | number[]
// res.c exists with type string | Set<string> | string[]
// but res.b does not exist, whereas it should have had type number