0

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:

  1. There are a finite amount of PackedValue types allowed, in this case 5
  2. The user must explicitly define all used PackValue types when calling unpackObj or those types will appear as an any type 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

1 Answer 1

2

Yes, there is a way using infer keyword:

type UnpackedValueOnly<T> = {
    [key in keyof T]: T[key] extends PackedValue<infer U> ? U : T[key]
}

Check this TS sandbox and hover over the Test to see that the initial type of the variable foo was

{
  a: string
  b: PackedValue<number[]>
  c: PackedValue<string>
}

And after unpacking it is

{
  a: string
  b: number[]
  c: string
}
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.