From 05d4224c2f2c8fe2edb6d912dcb5bbd681014be6 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 25 Feb 2019 14:11:01 -0800 Subject: [PATCH 1/5] Restore covariant comparison to bluebird's Promise Now that typescript@next checks variance more strictly for conditional types, bluebird's Promise is invariant. This PR removes conditional types from bluebird so that Promise compares covariantly again. Note that I never figured out how to do this for `call`, so it returns `Bluebird` right now. I'm still working on that. --- types/bluebird/index.d.ts | 46 ++++++++++++++++++++++++++++----------- 1 file changed, 33 insertions(+), 13 deletions(-) diff --git a/types/bluebird/index.d.ts b/types/bluebird/index.d.ts index 24c2b79a32..e8c6dbf5a2 100644 --- a/types/bluebird/index.d.ts +++ b/types/bluebird/index.d.ts @@ -37,8 +37,6 @@ type Constructor = new (...args: any[]) => E; type CatchFilter = ((error: E) => boolean) | (object & E); -type IterableItem = R extends Iterable ? U : never; -type IterableOrNever = Extract>; type Resolvable = R | PromiseLike; type IterateFunction = (item: T, index: number, arrayLength: number) => Resolvable; @@ -352,7 +350,7 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { * }); * */ - call(propertyName: U, ...args: any[]): Bluebird any ? ReturnType : never>; + call(propertyName: U, ...args: any[]): Bluebird; /** * This is a convenience method for doing: @@ -562,12 +560,17 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { /** * Like calling `.then`, but the fulfillment value or rejection reason is assumed to be an array, which is flattened to the formal parameters of the handlers. */ - spread(fulfilledHandler: (...values: Array>) => Resolvable): Bluebird; + spread(this: Bluebird>, fulfilledHandler: (...values: Array) => Resolvable): Bluebird; /** * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - all(): Bluebird>; + all(this: Bluebird>): Bluebird; + + /** + * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + all(): Bluebird; /** * Same as calling `Promise.props(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. @@ -578,42 +581,59 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { /** * Same as calling `Promise.any(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - any(): Bluebird>; + any(this: Bluebird>): Bluebird; + + /** + * Same as calling `Promise.any(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + any(): Bluebird; /** + * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - some(count: number): Bluebird>; + some(this: Bluebird>, count: number): Bluebird; + + /** + * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + some(count: number): Bluebird; /** * Same as calling `Promise.race(thisPromise, count)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - race(): Bluebird>; + race(this: Bluebird>): Bluebird; + + /** + * Same as calling `Promise.race(thisPromise, count)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. + */ + race(): Bluebird; /** * Same as calling `Bluebird.map(thisPromise, mapper)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - map(mapper: IterateFunction, U>, options?: Bluebird.ConcurrencyOption): Bluebird ? U[] : never>; + map(this: Bluebird>, mapper: IterateFunction, options?: Bluebird.ConcurrencyOption): Bluebird; /** * Same as calling `Promise.reduce(thisPromise, Function reducer, initialValue)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - reduce(reducer: (memo: U, item: IterableItem, index: number, arrayLength: number) => Resolvable, initialValue?: U): Bluebird ? U : never>; + reduce(this: Bluebird>, reducer: (memo: U, item: Q, index: number, arrayLength: number) => Resolvable, initialValue?: U): Bluebird; /** * Same as calling ``Promise.filter(thisPromise, filterer)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - filter(filterer: IterateFunction, boolean>, options?: Bluebird.ConcurrencyOption): Bluebird>; + filter(this: Bluebird>, filterer: IterateFunction, options?: Bluebird.ConcurrencyOption): Bluebird; /** * Same as calling ``Bluebird.each(thisPromise, iterator)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - each(iterator: IterateFunction, any>): Bluebird>; + each(this: Bluebird>, iterator: IterateFunction): Bluebird; /** * Same as calling ``Bluebird.mapSeries(thisPromise, iterator)``. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - mapSeries(iterator: IterateFunction, U>): Bluebird ? U[] : never>; + mapSeries(this: Bluebird>, iterator: IterateFunction): Bluebird; /** * Cancel this `promise`. Will not do anything if this promise is already settled or if the cancellation feature has not been enabled From 1a35aa7ea119f989a8bb96e1a5cd7c6eec1137a5 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 25 Feb 2019 14:28:36 -0800 Subject: [PATCH 2/5] Small cleanup 1. Fix Array<> lint 2. Use {} instead of unknown to continue targetting 2.9. 3. Update tests -- still no way to get anything but `any` from `call`. --- types/bluebird/bluebird-tests.ts | 2 +- types/bluebird/index.d.ts | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/types/bluebird/bluebird-tests.ts b/types/bluebird/bluebird-tests.ts index 05ac5cc19c..c7b1112a9e 100644 --- a/types/bluebird/bluebird-tests.ts +++ b/types/bluebird/bluebird-tests.ts @@ -553,7 +553,7 @@ bool = fooProm.isResolved(); strProm = fooProm.call("foo"); strProm = fooProm.call("foo", 1, 2, 3); -// $ExpectType Bluebird +// $ExpectType Bluebird quxProm.call("qux"); strProm = fooProm.get("foo").then(method => method()); diff --git a/types/bluebird/index.d.ts b/types/bluebird/index.d.ts index e8c6dbf5a2..efb43450eb 100644 --- a/types/bluebird/index.d.ts +++ b/types/bluebird/index.d.ts @@ -560,12 +560,12 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { /** * Like calling `.then`, but the fulfillment value or rejection reason is assumed to be an array, which is flattened to the formal parameters of the handlers. */ - spread(this: Bluebird>, fulfilledHandler: (...values: Array) => Resolvable): Bluebird; + spread(this: Bluebird>, fulfilledHandler: (...values: Q[]) => Resolvable): Bluebird; /** * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - all(this: Bluebird>): Bluebird; + all(this: Bluebird>): Bluebird; /** * Same as calling `Promise.all(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. @@ -592,7 +592,7 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. */ - some(this: Bluebird>, count: number): Bluebird; + some(this: Bluebird>, count: number): Bluebird; /** * Same as calling `Promise.some(thisPromise)`. With the exception that if this promise is bound to a value, the returned promise is bound to that value too. From 548c13e0191bedd8a9084a9cb87adcbc245a5733 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 25 Feb 2019 14:42:36 -0800 Subject: [PATCH 3/5] Add an unrelated type parameter and this parameter This returns `call` to its previous level of fidelity. Thanks (?) to @weswigham for this hack. --- types/bluebird/bluebird-tests.ts | 2 +- types/bluebird/index.d.ts | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/types/bluebird/bluebird-tests.ts b/types/bluebird/bluebird-tests.ts index c7b1112a9e..05ac5cc19c 100644 --- a/types/bluebird/bluebird-tests.ts +++ b/types/bluebird/bluebird-tests.ts @@ -553,7 +553,7 @@ bool = fooProm.isResolved(); strProm = fooProm.call("foo"); strProm = fooProm.call("foo", 1, 2, 3); -// $ExpectType Bluebird +// $ExpectType Bluebird quxProm.call("qux"); strProm = fooProm.get("foo").then(method => method()); diff --git a/types/bluebird/index.d.ts b/types/bluebird/index.d.ts index efb43450eb..13a11c2e3e 100644 --- a/types/bluebird/index.d.ts +++ b/types/bluebird/index.d.ts @@ -350,7 +350,7 @@ declare class Bluebird implements PromiseLike, Bluebird.Inspection { * }); * */ - call(propertyName: U, ...args: any[]): Bluebird; + call(this: Bluebird, propertyName: U, ...args: any[]): Bluebird any ? ReturnType : never>; /** * This is a convenience method for doing: From cbbd91a65dac1790f376332d870a5b600a99d7be Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Mon, 25 Feb 2019 15:27:34 -0800 Subject: [PATCH 4/5] Split bluebird-global function types Now they are based on bluebird types, but do not directly refer to them. That's because they. bluebird-global is rarely used so I don't think the duplication is a problem. --- types/bluebird-global/index.d.ts | 21 ++++++++++++--------- types/knex/knex-tests.ts | 1 + 2 files changed, 13 insertions(+), 9 deletions(-) diff --git a/types/bluebird-global/index.d.ts b/types/bluebird-global/index.d.ts index da33188dd1..f2baa334cd 100644 --- a/types/bluebird-global/index.d.ts +++ b/types/bluebird-global/index.d.ts @@ -113,12 +113,15 @@ import Bluebird = require("bluebird"); declare global { + type IterateFunction = (item: T, index: number, arrayLength: number) => (R | PromiseLike); /* * Patch all instance method */ interface Promise { - all: Bluebird["all"]; - any: Bluebird["any"]; + all(this: Promise>): Bluebird; + all(): Bluebird; + any(this: Promise>): Bluebird; + any(): Bluebird; asCallback: Bluebird["asCallback"]; bind: Bluebird["bind"]; call: Bluebird["call"]; @@ -128,9 +131,9 @@ declare global { delay: Bluebird["delay"]; disposer: Bluebird["disposer"]; done: Bluebird["done"]; - each: Bluebird["each"]; + each(this: Promise>, iterator: IterateFunction): Bluebird; error: Bluebird["error"]; - filter: Bluebird["filter"]; + filter(this: Promise>, filterer: IterateFunction, options?: Bluebird.ConcurrencyOption): Bluebird; // finally: Bluebird["finally"]; // Provided by lib.es2018.promise.d.ts get: Bluebird["get"]; isCancelled: Bluebird["isCancelled"]; @@ -139,17 +142,17 @@ declare global { isRejected: Bluebird["isRejected"]; isResolved: Bluebird["isResolved"]; lastly: Bluebird["lastly"]; - map: Bluebird["map"]; - mapSeries: Bluebird["mapSeries"]; + map(this: Promise>, mapper: IterateFunction, options?: Bluebird.ConcurrencyOption): Bluebird; + mapSeries(this: Promise>, iterator: IterateFunction): Bluebird; nodeify: Bluebird["nodeify"]; props: Bluebird["props"]; race: Bluebird["race"]; reason: Bluebird["reason"]; - reduce: Bluebird["reduce"]; + reduce(this: Promise>, reducer: (memo: U, item: Q, index: number, arrayLength: number) => (U | PromiseLike), initialValue?: U): Bluebird; reflect: Bluebird["reflect"]; return: Bluebird["return"]; - some: Bluebird["some"]; - spread: Bluebird["spread"]; + some(this: Promise>, count: number): Bluebird; + spread(this: Bluebird>, fulfilledHandler: (...values: Q[]) => (U | PromiseLike)): Bluebird; suppressUnhandledRejections: Bluebird["suppressUnhandledRejections"]; tap: Bluebird["tap"]; tapCatch: Bluebird["tapCatch"]; diff --git a/types/knex/knex-tests.ts b/types/knex/knex-tests.ts index 8b173c0887..ac0000ad9a 100644 --- a/types/knex/knex-tests.ts +++ b/types/knex/knex-tests.ts @@ -1111,6 +1111,7 @@ knex('users') // // Migrations // +const name = "test"; const config = { directory: "./migrations", extension: "js", From cce07b72c95171b2a357b91ad2ab9789f5f74973 Mon Sep 17 00:00:00 2001 From: Nathan Shively-Sanders <293473+sandersn@users.noreply.github.com> Date: Tue, 26 Feb 2019 08:50:36 -0800 Subject: [PATCH 5/5] Update race as well --- types/bluebird-global/index.d.ts | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/types/bluebird-global/index.d.ts b/types/bluebird-global/index.d.ts index f2baa334cd..8924a941df 100644 --- a/types/bluebird-global/index.d.ts +++ b/types/bluebird-global/index.d.ts @@ -146,7 +146,8 @@ declare global { mapSeries(this: Promise>, iterator: IterateFunction): Bluebird; nodeify: Bluebird["nodeify"]; props: Bluebird["props"]; - race: Bluebird["race"]; + race(this: Promise>): Bluebird; + race(): Bluebird; reason: Bluebird["reason"]; reduce(this: Promise>, reducer: (memo: U, item: Q, index: number, arrayLength: number) => (U | PromiseLike), initialValue?: U): Bluebird; reflect: Bluebird["reflect"];