I have a function that either:
- accepts a string search term, returning a
Promise
- 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:
- The type of
cb
is stillunknown
afterif(cb)
return res
cannot match the right type, i.e.Promise<Result[]>
How should I properly type such a function?
CodePudding user response:
As mentioned in the comments, conditional types don't really work used like this. To achieve the outcome you are looking for you need to use function overloading (as others have said)
Here is a suggested implementation:
function search(term: string): Promise<Result[]>
function search(term: string, cb: Callback): void
function search(term: string, cb?: Callback) {
const res = fetcher(term)
if(cb) {
res.then(data => cb(data))
return
}
return res
}
CodePudding user response:
Here is a way I found that I can get rid of the type errors
type Result = {id: string}
function fetcher(term: string): Promise<Result[]> {
return Promise.resolve([{id: 'foo'}, {id: 'bar'}])
}
type Callback = (results: Result[]) => void
function search<T extends Callback>(term: string, cb?: T ): T extends Callback ? void : Promise<Result[]> {
const res = fetcher(term)
if(cb) {
res.then(data => cb(data)) // ✅
}
return res as Promise<Result[]> & void// ✅
}
const promise = search('key') // ✅ Promise<Result[]>
const v = search('key', () => {}) // ✅ void
Of course I am using unsafe type assertion but function overloads is as unsafe us type assertion so