简体   繁体   中英

How to specify which overloaded function I want in Typescript?

I'm trying to promisify standard node fs.writeFile. I have typings for both node and bluebird which is my Promise lib of choice here:

const f = Promise.promisify(fs.writeFile)
return f(file, content); // Should be a promise

This does not work because:

[ts] Supplied parameters do not match any signature of call target. const f: (arg1: string) => Promise<{}>

So i chooses the wrong overloaded method because the call to promisify can't really know which I guess. Or maybe it's not even that, but something with the optional arguments, because these are the three overloaded writeFile:

export function writeFile(filename: string, data: any, callback?: (err: NodeJS.ErrnoException) => void): void;
export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: number; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;
export function writeFile(filename: string, data: any, options: { encoding?: string; mode?: string; flag?: string; }, callback?: (err: NodeJS.ErrnoException) => void): void;

promisify has lots of overloads for # of args and looks like this:

/**
 * Returns a function that will wrap the given `nodeFunction`. Instead of taking a callback, the returned function will return a promise whose fate is decided by the callback behavior of the given node function. The node function should conform to node.js convention of accepting a callback as last argument and calling that callback with error as the first argument and success value on the second argument.
 *
 * If the `nodeFunction` calls its callback with multiple success values, the fulfillment value will be an array of them.
 *
 * If you pass a `receiver`, the `nodeFunction` will be called as a method on the `receiver`.
 */
static promisify<T>(func: (callback: (err:any, result: T) => void) => void, receiver?: any): () => Promise<T>;
static promisify<T, A1>(func: (arg1: A1, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1) => Promise<T>;
static promisify<T, A1, A2>(func: (arg1: A1, arg2: A2, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2) => Promise<T>;
static promisify<T, A1, A2, A3>(func: (arg1: A1, arg2: A2, arg3: A3, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3) => Promise<T>;
static promisify<T, A1, A2, A3, A4>(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4) => Promise<T>;
static promisify<T, A1, A2, A3, A4, A5>(func: (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5, callback: (err: any, result: T) => void) => void, receiver?: any): (arg1: A1, arg2: A2, arg3: A3, arg4: A4, arg5: A5) => Promise<T>;
static promisify(nodeFunction: Function, receiver?: any): Function;

So it seems it rather the wrong promisify that is being used. Is there any cleaner way for me to achieve what I want? Currently I have to resolve to this:

const writeFile : (filename: string, data: any, callback: (err: NodeJS.ErrnoException) => void) => void = fs.writeFile
const f = Promise.promisify(writeFile)
return f(file, content); 

which I feel is very ugly and verbose…

I haven't been able to set up a good simple working example, but the following type assertion would allow you to hint and what you would expect:

const f = <(file: string, content: string) => void> Promise.promisify(fs.writeFile)

You can amend <(file: string, content: string) => void> to better describe what you expect to be available, or use the wider type <Function> or go dynamic with <any> .

The first option is a little more work, but will allow the return type to be inferred when you later call f (in this case void - but you can imagine cases where this return type will be used more vigorously).

Based on your comment, I'm guessing you'll need...

const f = <(file: string, content: string) => Promise<any>> Promise.promisify(fs.writeFile)

You could also use a union type in place of the any in this example, if you know the two possible outcomes, ie Promise<any> could be:

Promise<ErrnoException | MySuccessfulType>

This will allow a return type of Promise<ErrnoException> or a return type of Promise<MySuccessfulType> .

you could use __promisify__ from fs.writeFile namespace:

fs.writeFile.__promisify__(file, content)

Otherwise, you've to explicitly mention generic types to pick corresponding overload:

  • Node built-in util package has a promisify() function
const f = util.promisify<PathLike, string, void>(fs.writeFile)
f(file, content)

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM