Rigotti
Rigotti

Reputation: 2872

Conditional type when key is defined in object parameter

Is it possible to return a different type if an optional key in an object is defined. In the following code I try to explain what I am trying to achieve:

interface Model {
    name: string;
}

interface Arg {
    id?: number;
}

const func = (obj: Arg): Arg["id"] extends number ? Model : Model[] => {
    if (obj.id) {
        return eval(""); // will return Model;
    } else {
        return eval(""); // will return Model[];
    }
}

const all = func({}); // correct `Model[]` inference
const single = func({ id: 1 }); // expected inference `Model`, actually `Model[]`

Ignore the eval call here, in my actual code this is actually a service that returns any as well. What I'd like to have it back from this function is that everytime I pass an id to the object as argument, it returns a single Model otherwise Model[].

I expected the signature of my method to be correct

(obj: Arg): Arg["id"] extends number ? Model : Model[]

but that doesn't seem to be working, is there a way to get it back what I am expecting?

Typescript playground link

Upvotes: 0

Views: 173

Answers (1)

lukasgeiter
lukasgeiter

Reputation: 153140

Arg["id"] will always get you number | undefined. You have to make the function generic:

const func = <T extends Arg>(obj: T): T["id"] extends number ? Model : Model[] => {
    if (obj.id) {
        return eval(""); // will return Model;
    } else {
        return eval(""); // will return Model[];
    }
}

Now T refers to the type of the actual argument and not the Arg interface.

Playground

Upvotes: 1

Related Questions