0

here is a playground:

https://www.typescriptlang.org/play?target=9#code/C4TwDgpgBAjlC8UDeBYAUFKBtA1hEAXFAM7ABOAlgHYDmAukahplAPYBGAVgIxECGVEABp0LNlwBM-QWPQBfOenQBjVlVKwArgmSjYU3c0wceRAOTAIpMyKPjOBi1eASzstHNuYYAZkZ7jLl4oCS8WEwMJHwAWdwUlNBU1DRhNCDIQADEqHQAeABUoCAAPSyoAE2JYAD4AChMifIBKBGqoXIBpItKICqq8EFYAMyh8upgiDqbGrA66LDMTbjM6VsNMVXVgZCWhewk5HRMsGDo9MghgTTIcpfkEjeTt1LIdVPSsqlrUpoTNjWIrAAthBWMAABbpIY5RC1PhkGhEAAK8L4IMsZGIuVAkGGWjI1SwAAY6C14G0mJgADaXKAXYhEABKl2uVHy4Ag2I5eJeXNxI3hNGq1XOVje1zhCN+zAuVxudKs90SaH+23pOkBILBkLI0NqZl8ZhaAHpjVAaBQAG7UGhQEFQPhQTRUChqKDUUgQPjlNgjahDdKUWhQVRkC7KbY4iAJdBAA

Basically having a function where I can send in an argument that returns some value. It gives me a union however since there are keys with the same name that have different types:

const qu = {
  q2: {
    obj1: 'test',
    obj2: 'test2'    
},
  q3: {
    obj1: 2,
    obj2: 234    
}}

is there a way to infer the type? I've tried with conditionals but with no luck. Or is this a TS limitation?

Here is full code example:

type q = {
  [key: string]: {
    obj1: any,
    obj2: any    
}}

const qu = {
  q2: {
    obj1: 'test',
    obj2: 'test2'    
},
  q3: {
    obj1: 2,
    obj2: 234    
}}


const queryFn = <T extends q>(obj: T) => <K extends keyof T>(q: K): T[K]['obj1'] => {
  const {obj1, obj2} = obj[q]
  return obj1
}

  const qur = queryFn(qu)

const someotherfn = (arg: Parameters<typeof qur>[0]) => {
  let res: ReturnType<typeof qur<typeof arg>>
  res = qur(arg)
  return res
}

const res = someotherfn('q3') // giving me a union instead of inferring correct type
Martin
  • 99
  • 5
  • Please [edit] to include the code example directly in the question as plain text; a playground link is a nice supplement, but we can't require people navigate away from SO to see the relevant code. After you do that, is [this approach](https://tsplay.dev/NB5jnw) what you're looking for? If so I could write up an answer. If not, what am I missing? – jcalz Oct 09 '22 at 19:44
  • thanks @jcalz - i added the remaining parts of the code. yes, your solution works, thanks! so the generics do the magic i have one more ask - I want to curry a function and make sure the return type gets inferred. I realized you can't do higher order generics K for example. Is this my answer to the problem? https://stackoverflow.com/questions/60007436/higher-order-type-functions-in-typescript – Martin Oct 10 '22 at 06:31
  • You might be able to get the right sort of inference with currying, since [there is some support for higher order function type inference](https://www.typescriptlang.org/docs/handbook/release-notes/typescript-3-4.html#higher-order-type-inference-from-generic-functions) but without a [mre] I don't know. Sounds like a separate question, though, and thus out of scope here... so if you can't find an answer you might want to make a new post. I'll write up an answer for the question as asked when I get a chance. – jcalz Oct 10 '22 at 13:04

1 Answers1

1

The problem here is that someotherfn is not itself generic; if you don't explicitly annotate the call signature as generic, then the return type someotherfn will not depend on its input type.

The fix could look like this:

const someotherfn = <K extends Parameters<typeof qur>[0]>(arg: K) => {
  let res: ReturnType<typeof qur<K>>
  res = qur(arg)
  return res
}

where we just make the function generic in K, the type of arg. Now things behave as expected:

const res = someotherfn('q3');
// const res: number

Playground link to code

jcalz
  • 264,269
  • 27
  • 359
  • 360