typescript

How to make TypeScript typeof types to the type itself?


Let's pretend I have a function. It's a very nice function, very friendly. And it takes an argument, let's call it type. But guess what? It's actually a string! Here, let me give you an example:

function returnWithType(o: any, type: 'string' | 'number') {
  if (typeof o === type) return o
  throw new Error(`AHHHH!!!!!`)
}

See what I did there? I checked the type against the type!

But, okay now let me ask you this... how can I specify the function's actual return type, so that if they pass "string" then the return type is string, and the same for number, but with "number" instead of "string" assuming they passed the string value "number" into the second parameter in this case???

I basically want this:

function returnWithType(o: any, type: 'string' | 'number'):
  asserts typeof o === as // <---- THIS
{
  // ...
}

Or maybe this:

function returnWithType(...):
  type extends 'string' ? string :
  type extends 'number' ? number :
  boolean
{
  // ... solves world hunger ...
}

I just realized I can do this by creating the generic T extends ... and returning a ternery based on T, but is there any cleaner way, maybe with some clever builtins, to derive this information automatically???


Solution

  • To avoid many conditional types you could use a map type:

    Playground

    type Types = {
      string: string,
      number: number
    }
    
    function returnWithType<K extends keyof Types>(o: any, type: K): Types[K]  {
      if (typeof o === type) return o
      throw new Error(`AHHHH!!!!!`)
    }
    
    const str = returnWithType('string', 'string'); // string
    const num = returnWithType(2, 'number'); // number