typescripttypescript-generics

TypeScript mapping function with conditional types


given the following example:

type V0Input = {
  version: '0'
};

type V1Input = {
  version: '1'
}

type AnyInput = V0Input | V1Input;

type V0Output = {
  a: string
}

type V1Output = {
  b: string
}

type Ret<I> = I extends V0Input ? V0Output : V1Output

const fn = <I extends AnyInput>(i: I): Ret<I> => i.version === '0' ?
  {a: ''} as Ret<I> :
  {b: ''} as Ret<I>
;

Did anyone found out a way to remove those casts? I've started using something like that without casts (taking lambda parametrized by outer I), but it turns out that my method doesn't work for all kind of objects.


Solution

  • use function overload

    type V0Input = {
      version: '0'
    };
    
    type V1Input = {
      version: '1'
    }
    
    type AnyInput = V0Input | V1Input;
    
    type V0Output = {
      a: string
    }
    
    type V1Output = {
      b: string
    }
    
    function fn(input: V0Input): V0Output;
    function fn(input: V1Input): V1Output;
    
    // here is implementation
    function fn(input: AnyInput): V0Output | V1Output {
      if (input.version === '0') {
        return { a: '' }; // Inferred as V0Output
      } else {
        return { b: '' }; // Inferred as V1Output
      }
    }
    

    expected outtput will be

    const result0 = fn({ version: '0' }); // V0Output
    const result1 = fn({ version: '1' }); // V1Output