2

There are two function types, one returns string and other one returns a Promise<string>. Now I'd like to have a function to wrap them, but I have to distinguish each one while invoking fn

type FuncTypes = (...args: any[]) => string | Promise<string>

function callFunc(fn: FuncTypes, ...args: any[]) {
  // distinguish fn returns string or Promise<string>
  // if fn returns string
    return new Promise<string>(r => r(fn.call(this, ...args)))
  // if fn returns a Promise
    return fn.call(this, ...args)
}

Another situation is overload:

type FuncA = (...args: any[]) => string
type FuncB = (...args: any[]) => Promise<string>

function callFunc(fn: FuncA, ...args: any[]): Promise<string>
function callFunc(fn: FuncB, ...args: any[]): Promise<string>
function callFunc(fn: any, ...args: any[]): Promise<string> {
  // if fn is instanceof FuncA
  // do sth.
  // else if fn is instanceof FuncB
  // do sth
}

Although we can simply use const returned = fn(..args); typeof returned === 'string' to check returned type, it is not a general solution. If function type is () => AnInterface|AnotherInterface, it's difficult to check return type by using typeof or instanceof.

Is there any general way to distinguish them? or should I write two functions for each type?

1 Answer 1

1

In that specific case

There are two function types, one returns string and other one returns a Promise. Now I'd like to have a function to wrap them, but I have to distinguish each one while invoking fn

In that specific case, callFunc can just be this:

function callFunc(fn: FuncTypes, ...args: any[]) {
    return <Promise<string>>Promise.resolve(fn.call(this, ...args));
}

If fn returns a promise, the promise from Promise.resolve will be resolved to the promise returned by fn (it will wait for that promise to settle and settle the same way); if it doesn't, you'll have a fulfilled promise with the return value of fn as its resolution value.

In the general case

Is there any general way to distinguish them?

Not at runtime, unless you annotate them in some way (more in a moment). TypeScript's type information is compile-time only.

or should I write two functions for each type?

That's probably best.

You could annotate the functions, for instance by putting a property on them indicating what their return type is:

function delay(ms: number, value: string): Promise<string> {
    return new Promise<string>(resolve => setTimeout(resolve, ms, value));
}
(<any>delay).returnValue = "Promise<string>";

At that point, you're duplicating the type information (once for TypeScript, again for your own code).

So your solution of writing two functions is probably best.

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

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.