laptou
laptou

Reputation: 6981

Type guard: every type except a certain type

In TypeScript, I am trying to create a type guard for a function that allows type parameter T to be any type that is not a Function like this:

type Thunk<T> = (() => T) | T;

function unthunk<T extends Exclude<any, Function>>(x: Thunk<T>): T
{
    if (typeof x === "function") return x();
    return x;
}

But I am getting this error:

TS2349 Cannot invoke an expression whose type lacks a call signature. Type '(() => T) | (T & Function)' has no compatible call signatures.

How can I get my intended result? I am using TypeScript 3.4.

Edit: It seems that the typeof x === "function" is causing the error, and I can work around that by simply casting x. However, the type guard still does not work:

function unthunk<T extends Exclude<any, Function>>(x: Thunk<T>): T
{
    if (typeof x === "function") return (x as () => T)();
    return x;
}

unthunk<() => number>(() => () => 3); // there should be an error here but there is none

Upvotes: 0

Views: 292

Answers (1)

zerkms
zerkms

Reputation: 254906

Wouldn't function overload do what you want

function unthunk<T>(x: () => T extends Function ? never : T): T;
function unthunk<T>(x: T extends Function ? never : T): T;

function unthunk<T>(x: T): T {
    if (typeof x === 'function') { 
        return x();
    }

    return x;
}

const a = unthunk(1);
const b = unthunk(() => 1);
const c = unthunk(() => () => 1);

Playground

Upvotes: 1

Related Questions