TypeScript type definition for promise.prototype.finally
Solution 1
Whilst the answer from Slava is correct, it only deals with the typing of the finally
block. To actually incorporate the shim into your code, so you can write p.finally(() => { ... })
, you need to invoke the shim.
Unfortunately the typings on DefinitelyTyped do not currently support the shim
function so until this is supported, I'd advise to add the typings yourself.
declare interface Promise<T> {
finally<U>(onFinally?: () => U | Promise<U>): Promise<U>;
}
declare module 'promise.prototype.finally' {
export function shim(): void;
}
The types are now available. Install with
npm install --save-dev @types/promise.prototype.finally
In your TypeScript code, during application bootstrap, you can then call
import { shim } from 'promise.prototype.finally';
shim();
This will add the finally
block to the Promise
prototype, allowing you to use finally
as required.
Solution 2
For anyone wondering how to get this working natively without any shims: as of TS 2.7 it's possible.
Note that TS 2.7 is not yet fully (26. Feb. 2018) ES2018 compatible. While there are still a few things missing, Promise.finally made it into the 2.7 release. Also tsconfig-schema should already accept ES2018 as target but yet TS 2.7 has no knowledge of ES2018. For now to use the new features, such as Promise.finally, which already are in 2.7, you'll have to use "target": "ESNEXT"
in your tsconfig.json.
Then you'll be able to write code like this:
myAsyncFunction().then
(
(var) => console.log("executing then. " + var)
)
.catch
(
(var) => console.log("executing catch. " + var)
)
.finally
(
() => console.log("executing finally.")
)
Notice how finally will not take any arguments due to it's nature.
IMPORTANT: while TS will transpile correctly and understand what you're doing you still have to check if your JS-Engine supports Promise.finally. In my case I was using NodeJs 8.x and of course the produced JS was not executable because Promise.Finally is supported starting with in the latest NodeJs 10.x nightly builds Node 10.x (stable), see this link.
Solution 3
You can write your own d.ts file and reference it in the tsconfig.json file. Of you do it you can contribute to the DefinitelyTyped git for others like yourself
Update:
If I understood correctly what you mean you can extend the existing Promise
class in your own d.ts file. Make the method to be optional so it won't tell you the actual Promise
class is not implementing the interface correctly.
You need to extend it as an interface.
Your d.ts file should look like this
declare module 'es6-promise/dist/es6-promise' {
export interface Promise <R> {
finally?<U>(onFinally?: () => U | Promise<U>): Promise<U>;
}
}
And it should work properly...
I created a project for you as an example: promise-extension-typescript-example
I created a pull request to the DefinitelyTyped git repository, hope it will be accepted and you can download it from there...
Related videos on Youtube
jpierson
Updated on June 04, 2022Comments
-
jpierson almost 2 years
I was using this ES6 Promise compatible finally implementation called promise.prototype.finally in a Node application that I want to convert to TypeScript however there are no typing available for this package that I can find on DefinitelyTyped. In these situations I've written up my own impromptu type definitions for just the subset of functionality that I need but in this case it is a library that modifies the prototype of the Promise object and I haven't encountered any conventional way to represent this in TypeScript. Any ideas?
Possibly related:
-
jpierson about 8 yearsI'm definitely aware of these points. The situation I'm describing above is specific to that package where it is modifying an existing object/class instead of defining a new type or set of types.
-
jpierson about 8 yearsI'm not sure about
Thenable
but I'm working with promises as defined in the ES6 polyfilles6-promise
but promise.prototype.finally is supposed to support any ES5 compatible promise implementation. The type I'm working with is Promise<any>. Substituting Thenable with Promise in your implementation above doesn't work for me because tsc gives me an error at the site of the import for the Promise polyfillimport { Promise } from 'es6-promise';
. -
Slava Shpitalny about 8 yearsIf you looke in the d.ts file es6-promise you will see that
Promise
implements theThenable
. On the code I gave you I extend that interface with a new method -
jpierson about 8 yearsFrom what I can see as described above, extending an interface by writing a new interface with the same name doesn't appear to be compatible with the TypeScript compiler.
-
Slava Shpitalny about 8 yearsYou can see it works file here: Typescript Playground
-
jpierson about 8 yearsSeems to work there but I get an error "Import declaration conflicts with local declaration of 'Thenable' interface Thenable<T>" by importing via
import { Promise, Thenable } from 'es6-promise';
followed by the code block that you posted above. Perhaps only interfaces in the local module scope can be modified in this way? -
Slava Shpitalny about 8 yearsDid you define the interface in another d.ts file and added it to the tsconfig.json or just added it to the ts file?
-
Slava Shpitalny about 8 yearsI added another d.ts file and it worked too well, it errored that the Promise is not implementing the interface correctly, I'll look into that
-
Slava Shpitalny about 8 yearsI updated the answer with making the method optional and putting the interface inside the module
-
jpierson about 8 yearsLet us continue this discussion in chat.
-
Slava Shpitalny about 8 yearsI think my edited answer should answer your question now
-
omni about 6 yearsUhm I can't get this working with Visual Studio Code 1.20 - It'll build but when running the code I'll get a "Cannot find module 'promise.prototype.finally'" error, altought the module is available in node_modules@types. Wonder if that's even worth investigating since github.com/Microsoft/TypeScript/issues/20411 added native support for "finally", finally.
-
zed almost 6 yearsJust using
yarn add @types/promise.prototype.finally --dev
did it for me