0

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

1 Answer 1

1

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

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

2 Comments

That works, thanks for it. Although I can't seem to understand why a generic extending that interface is not the same as the direct access to the value...
Arg is always the interface, no matter what value you pass to the function. The generic T however is the type of the argument value. e.g. {} in the first call and { id: number } in the second.

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.