Home > Software engineering >  How to limit generic return type in Typescript?
How to limit generic return type in Typescript?

Time:04-26

I want to make a function that will try running provided function, and will throw unless it returns a truthy value, like this:

function test<T>(runnable: () => T): T {
    const value = runnable();
    if (! value) throw new Error(`Only truthy`);
    return value;
}

const a = test(() => {
    return (Math.random() < 0.5) ? undefined : "ok";
});

console.log(a);

How do I change the definition of test so that TS knows that a is always a string, not string|undefined?

CodePudding user response:

If you make the falsy types part of inner function return type, but not part of the outer function type, then this is possible:

First, make a Falsy type alias:

type Falsy = false | null | undefined | 0 | ''

And now make a union with T for the inner function return type:

function test<T>(runnable: () => T | Falsy): T {
    const value = runnable();
    if (!value) throw new Error(`Only truthy`);
    return value;
}

This means that T is inferred to not include the Falsy types. And the inner runnable function is allowed to return T or any Falsy type. Then you check for the Falsy type and proceed to the return only if the value is not a Falsy, which must be a T.

Now this function has a return type of "ok" since the error traps all other results.

const a = test(() => {
    return (Math.random() < 0.5) ? undefined : "ok";
});

a // type: "ok"

Playground

  • Related