Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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…

like image 209
Viktor Hedefalk Avatar asked Jun 15 '16 10:06

Viktor Hedefalk


1 Answers

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)
like image 190
am0wa Avatar answered Sep 25 '22 14:09

am0wa