'Return different type by string in Typescript

Given we have two different types as below, how can we change the return of function based on a string parameter and not providing the generic type?

interface Type1 { typeName: string; };
interface Type2 { typeVersion: string; };
type AllTypes = Type1 | Type2;

function returnTypes(t: string): AllTypes {
  ...
}

const typeResult = returnTypes('type1');
console.log(typeResult.typeName);

Here the return is not defined!



Solution 1:[1]

Create an overloaded declaration like so

interface Type1 { typeName: string; };
interface Type2 { typeVersion: string; };
type AllTypes = Type1 | Type2;

function returnTypes(t: 'type1'): Type1;
function returnTypes(t: 'type2'): Type2;
function returnTypes(t : 'type1' | 'type2'): AllTypes {
    switch (t) {
        case "type1": return { typeName: "test" };
        case "type2": return { typeVersion: "test" };
    }
}

console.log(returnTypes('type1').typeName);
console.log(returnTypes('type2').typeVersion);

Note that when you overload a function in this manner, the implementation signature is not available to callers. Only the declarations specified beforehand comprise an overloaded function's interface.

UPDATE: Fixed and completed example to show that TypeScript knows which type it is returning.

Solution 2:[2]

You could use a template type https://www.typescriptlang.org/docs/handbook/generics.html

private returnTypes<T>(arg:T): T {
    return arg
}

Otherwise you'd have to set switch cases based on your arg

returnTypes(arg:string): AllTypes {
    switch(arg){
        case "type1": return SomethingOfType1
        case "type2": return SomethingOfType2
    }
}

A bit more information about what you're trying to accomplish might help.

Solution 3:[3]

I am not sure what you are trying to do, but it seems like you are trying to define a function that returns one of several types. So for example the function would return either Type1 or Type2. Unless the two types share a common set of functionality, you would then need to check the type before calling a potentially different method on the returned object.

Assuming the objects you are returning do share a common set of functionality, it would be better to define that in an interface and then declare that each object type you want to return implements that interface.

So as an example.

interface CommonStuff {
  someFunction();
  someOtherFunction();
}

class Type1 implements CommonStuff {
  someFunction() {}
  someOtherFunction() {}
}  

class Type2 implements CommonStuff {
  someFunction() {}
  someOtherFunction() {}
}

Then simply have your function return a type of CommonStuff

returnTypes(str:String) : CommonStuff {
   let x : Type1;
   let y : Type2;
   ...
   const z = someCondition ? x : y ;
   return z;
}

This avoids needing to check the type later

const something = returnTypes("blah);
something.someFunction();  // you know something has a someFunction() method.

Solution 4:[4]

Let's say I have an array of objects with different types. All objects have the same field ID. My task is to extract one object by ID. And I want to make sure that object has specific type. I don't want to use question marks in my types.

Here is my solution -

interface Object1 { 
    id: string;
    color: string; 
};

interface Object2 { 
    id: string;
    age: number; 
};

type ObjectType = Object1 | Object2;

function getObject(arr: any, id: '101'): Object1;

function getObject(arr: any, id: '102'): Object2;

function getObject(arr: any, id : '101' | '102'): ObjectType {
    return arr.find((item) => item.id === id);
}

const arr = [
    {
        id: '101',
        color: 'white',
    },
    {
        id: '102',
        age: 12,
    }
]

console.log(getObject(arr, '101').color);
console.log(getObject(arr, '102').age);

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1 Rodris
Solution 2 Shai James
Solution 3 nPn
Solution 4 Dmitry Grinko