I'm trying to write a function with a return type, UnpackedValuesOnly, that can dynamically determine the type of a "packed" value K without the user having to explicitly define what K is.
Here's as close as I've been able to come:
//pretend that this is a useful class for some reason
class PackedValue<T> {
value: T
constructor(value: T) {
this.value = value
}
}
//This is my best attempt at dynamically unpacking the type of a PackedValue
type UnpackedValuesOnly<T, K = any, K2 = any, K3 = any, K4 = any, K5 = any> = {
[P in keyof T]: T[P] extends PackedValue<K>
? K
: T[P] extends PackedValue<K2>
? K2
: T[P] extends PackedValue<K3>
? K3
: T[P] extends PackedValue<K4>
? K4
: T[P] extends PackedValue<K5>
? K5
: UnpackedValuesOnly<T[P], K, K2, K3, K4, K5>
}
const unpackObj = <T, K = any, K2 = any, K3 = any, K4 = any, K5 = any>(toUnpack: T): UnpackedValuesOnly<T, K, K2, K3, K4, K5> => {
//implementation unimportant, assume that non packed values are preserved, packed values are unpacked
return {} as any as UnpackedValuesOnly<T, K, K2, K3, K4, K5>
}
const foo = {
a: 'hello',
b: new PackedValue([ 1, 3 ]),
c: new PackedValue('asdf')
}
const bar = unpackObj<typeof foo, number[]>(foo)
//type of string
bar.a
//type of number[]
bar.b
//type of any
bar.c
The above has a few major downsides:
- There are a finite amount of
PackedValuetypes allowed, in this case 5 - The user must explicitly define all used
PackValuetypes when callingunpackObjor those types will appear as ananytype and lose all compiler checking
Is there a way of writing UnpackedValuesOnly so that the below example code will allow the compiler/linter to report the correct types by implicitly determining the type of PackedValue?
const bar = unpackObj(foo) // or maybe unpackObj<typeof foo>(foo)
//type of string
bar.a
//type of number[]
bar.b
//type of string
bar.c