1

So I am trying to get an object based on the parameter being passed in. I found this question and it get really close to what I after. TypeScript function return type based on input parameter However, I want the function to be able to accept string too, and when the parameters passed in is not in the literal type, it will infer any or unknown

Let me put what I mean in code.

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}

type TypeName = "circle" | "square" | string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

Notice that TypeName has union type of literal type and string. What I hope to see if that, when I use the type, I would be able to infer the return type based on the parameter. For example:

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: unknown

The above is all good. However, I could not get the IDE to suggest the options. I expect to see an options of: 'circle' | 'square' | string.

Is that possible to do?

4
  • If you remove the | string option in TypeName it should work in your IDE. Or you can add something like type TypeName = "circle" | "square" | "unknown"; Commented Sep 3, 2020 at 11:09
  • Yes. But, it will have type error when I put the string 'unknown' in the param. I expect the function to infers unknown type. Commented Sep 3, 2020 at 11:14
  • following this codesandbox there seems to be no type error and if you hover over the called function it has the right type, am i missing something? Commented Sep 3, 2020 at 11:35
  • Thanks for the answer @Stutje. The type in the example is type TypeName = "circle" | "square" | "unknown";. However, I want type TypeName = "circle" | "square" | string;, the actual string type. The reason behind it is that if the type is not Literal Type that I specified, I would like to use the type value as is. Commented Sep 3, 2020 at 11:46

2 Answers 2

2

No, that's not possible because string is super type of string literal so

type TypeName = "circle" | "square" | string; 

is no different than

type TypeName = string; 

However, you could use function overloading to achieve your goal

type TypeName = "circle" | "square"
type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    never

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]
function getItems(type: string) : unknown[]
function getItems(type: string) {
  // implementation comes here
}

anyway, here's a new hack

type TypeName = "circle" | "square" | {} & string; 

type ObjectType<T> = 
    T extends "circle" ? Circle :
    T extends "square" ? Square :
    unknown;

function getItems<T extends TypeName>(type: T) : ObjectType<T>[]  {
    ...
}

try it yourself

Sign up to request clarification or add additional context in comments.

2 Comments

Thank you for taking time to answer @Austraras. However, the solution doesn't look like it's working. I created a codepen here
you missed 2nd overload and go directly to implentation
0

You can do this using overloads and a few conditional utility types:

interface Circle {
    type: "circle";
    radius: number;
}

interface Square {
    type: "square";
    length: number;
}


type KnownObject = Circle | Square
type IsKnownTypeName<T extends string, U = KnownObject> = U extends { type: T } ? T : never
type ObjectForType<T extends string, U = KnownObject> = U extends { type: T } ? U : never

function getItems<T extends string>(type: IsKnownTypeName<T>) : ObjectForType<T>[]
function getItems<T extends string>(type: T) : any[]
function getItems<T extends string>(type: T) : any[] {
    return []
}

const circle = getItems('circle'); // infers: Circle
const something = getItems('unknown'); // infers: any

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.