Reputation: 5611
I have a function that either:
Promise
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:
cb
is still unknown
after if(cb)
return res
cannot match the right type, i.e. Promise<Result[]>
How should I properly type such a function?
Upvotes: 1
Views: 166
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