Joji
Joji

Reputation: 5611

Conditional types don't narrow properly

I have a function that either:

  1. accepts a string search term, returning a Promise
  2. accepts a string search term and a callback function, returning nothing (void)

Here is my implementation:

function fetcher(term: string): Promise<Result[]> {
    return Promise.resolve([{id: 'foo'}, {id: 'bar'}])
}

type Callback = (results: Result[]) => void
function search<T>(term: string, cb?: T ): T extends Callback ?  void : Promise<Result[]> {
    const res = fetcher(term)

    if(cb) {
        res.then(data => cb(data)) // ❌  Type 'unknown' has no call signatures.(2349)
    } 

    return res // ❌ Type 'Promise<Result[]>' is not assignable to type 'T extends Callback ? Promise<Result[]> : void'.
}

const promise = search('key') // ✅ Promise<Result[]>
const v = search('key', () => {})  // ✅ void

There are two issues with this:

  1. The type of cb is still unknown after if(cb)
  2. return res cannot match the right type, i.e. Promise<Result[]>

How should I properly type such a function?

Upvotes: 1

Views: 166

Answers (1)

valerii15298
valerii15298

Reputation: 870

Actually just for you to know:) it is possible to achieve the same thing without overloads using just conditionals even in more than one way. Just for you to note, here is one way to achieve it:

type Result = { id: string };

function fetcher(term: string): Promise<Result[]> {
  return Promise.resolve([{ id: "foo" }, { id: "bar" }]);
}

type Callback = (results: Result[]) => void;

type RetType<T> = [T] extends [Callback] ? void : Promise<Result[]>;
function search<T extends Callback | undefined>(
  term: string,
  cb?: T
): RetType<T> {
  const res = fetcher(term);

  if (cb) {
    res.then((data) => cb(data));
    return undefined as RetType<T>; // need to use as
  }

  return res as RetType<T>;
}

const promise = search("key"); // ✅ Promise<Result[]>
const vjj = search("key", () => undefined); // ✅ void

But I would not recommend it as overloads look cleaner.

Upvotes: 2

Related Questions