[@types/when] Make when.js promises compatible with native promises (#24904)

* Make when.js promises compatible with native promises

* Stricter compiler options and fix revealed issues

- Remove optional parameters from callbacks
- Replace `Number` type with `number`
- Improve type checking of when.settle and promise.inspect

* Add stricter types and backwards compatibility

* Minor renaming
This commit is contained in:
Su-Shing Chen
2018-04-18 12:45:15 -07:00
committed by Ryan Cavanaugh
parent 3cb9ea62c0
commit eabc8ca762
3 changed files with 115 additions and 31 deletions
+49 -21
View File
@@ -109,7 +109,7 @@ declare namespace When {
* @returns a promise that will fulfill with an array of mapped values
* or reject if any input promise rejects.
*/
function map<T>(promisesOrValues: any[], mapFunc: (value: any, index?: Number) => any): Promise<T>;
function map<T>(promisesOrValues: any[], mapFunc: (value: any, index: number) => any): Promise<T>;
/**
* Traditional reduce function, similar to `Array.prototype.reduce()`, but
@@ -118,10 +118,10 @@ declare namespace When {
* be a promise for the starting value.
* @param promisesOrValues array or promise for an array of anything,
* may contain a mix of promises and values.
* @param reduceFunc function(accumulated:*, x:*, index:Number):*} f reduce function
* @param reduceFunc function(accumulated:*, x:*, index:number):*} f reduce function
* @returns a promise that will resolve to the final reduced value
*/
function reduce<T>(promisesOrValues: any[], reduceFunc: (reduction: T, value: any, index?: Number) => T | Promise<T>, initialValue: T): Promise<T>;
function reduce<T>(promisesOrValues: any[], reduceFunc: (reduction: T, value: any, index: number) => T | Promise<T>, initialValue: T): Promise<T>;
/**
* Traditional reduce function, similar to `Array.prototype.reduceRight()`, but
@@ -130,22 +130,38 @@ declare namespace When {
* be a promise for the starting value.
* @param promisesOrValues array or promise for an array of anything,
* may contain a mix of promises and values.
* @param reduceFunc function(accumulated:*, x:*, index:Number):*} f reduce function
* @param reduceFunc function(accumulated:*, x:*, index:number):*} f reduce function
* @returns a promise that will resolve to the final reduced value
*/
function reduceRight<T>(promisesOrValues: any[], reduceFunc: (reduction: T, value: any, index?: Number) => T | Promise<T>, initialValue: T): Promise<T>;
function reduceRight<T>(promisesOrValues: any[], reduceFunc: (reduction: T, value: any, index: number) => T | Promise<T>, initialValue: T): Promise<T>;
/**
* Describes the status of a promise.
* Describes the outcome of a promise.
* state may be one of:
* "fulfilled" - the promise has resolved
* "pending" - the promise is still pending to resolve/reject
* "rejected" - the promise has rejected
*/
interface Descriptor<T> {
state: string;
value?: T;
reason?: any;
type Descriptor<T> = FulfilledDescriptor<T> | RejectedDescriptor;
/**
* Snapshot which describes the status of a promise.
* state may be one of:
* "fulfilled" - the promise has resolved
* "rejected" - the promise has rejected
* "pending" - the promise is still pending to resolve/reject
*/
type Snapshot<T> = FulfilledDescriptor<T> | RejectedDescriptor | PendingDescriptor;
interface FulfilledDescriptor<T> {
state: 'fulfilled';
value: T;
}
interface RejectedDescriptor {
state: 'rejected';
reason: any;
}
interface PendingDescriptor {
state: 'pending';
}
/**
@@ -269,7 +285,26 @@ declare namespace When {
// be a constructor with prototype set to an instance of Error.
otherwise<U>(exceptionType: any, onRejected?: (reason: any) => U | Promise<U>): Promise<U>;
then<U>(onFulfilled: (value: T) => U | Promise<U>, onRejected?: (reason: any) => U | Promise<U>, onProgress?: (update: any) => void): Promise<U>;
then(
onFulfilled?: ((value: T) => T | Thenable<T>) | undefined | null,
onRejected?: ((reason: any) => T | Thenable<T>) | undefined | null,
onProgress?: (update: any) => void
): Promise<T>;
then<TResult>(
onFulfilled: ((value: T) => TResult | Thenable<TResult>),
onRejected?: ((reason: any) => TResult | Thenable<TResult>) | undefined | null,
onProgress?: (update: any) => void
): Promise<TResult>;
then<TResult>(
onFulfilled: ((value: T) => T | Thenable<T>) | undefined | null,
onRejected: ((reason: any) => TResult | Thenable<TResult>),
onProgress?: (update: any) => void
): Promise<T | TResult>;
then<TResult1, TResult2>(
onFulfilled: ((value: T) => TResult1 | Thenable<TResult1>),
onRejected: ((reason: any) => TResult2 | Thenable<TResult2>),
onProgress?: (update: any) => void
): Promise<TResult1 | TResult2>;
spread<T>(onFulfilled: _.Fn0<Promise<T> | T>): Promise<T>;
spread<A1, T>(onFulfilled: _.Fn1<A1, Promise<T> | T>): Promise<T>;
@@ -284,13 +319,7 @@ declare namespace When {
}
interface Thenable<T> {
then<U>(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U): Thenable<U>;
}
interface Snapshot<T> {
state: string;
value?: T;
reason?: any;
then<U>(onFulfilled?: (value: T) => U, onRejected?: (reason: any) => U): Thenable<U>;
}
}
@@ -369,8 +398,7 @@ declare module "when/node" {
interface Resolver<T> {
reject(reason: any): void;
resolve(value?: T): void;
resolve(value?: when.Promise<T>): void;
resolve(value?: T | when.Promise<T>): void;
}
function createCallback<TArg>(resolver: Resolver<TArg>): (err: any, arg: TArg) => void;
+3 -3
View File
@@ -6,8 +6,8 @@
],
"noImplicitAny": true,
"noImplicitThis": true,
"strictNullChecks": false,
"strictFunctionTypes": false,
"strictNullChecks": true,
"strictFunctionTypes": true,
"baseUrl": "../",
"typeRoots": [
"../"
@@ -20,4 +20,4 @@
"index.d.ts",
"when-tests.ts"
]
}
}
+63 -7
View File
@@ -10,13 +10,17 @@ class ForeignPromise<T> {
constructor(private readonly value: T) {
}
then<U>(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U) { return new ForeignPromise<U>(onFulfilled(this.value)); }
then<U>(onFulfilled?: (value: T) => U, onRejected?: (reason: any) => U): ForeignPromise<U>
then(onFulfilled?: (value: T) => T, onRejected?: (reason: any) => T): ForeignPromise<T> {
return new ForeignPromise(onFulfilled ? onFulfilled(this.value) : this.value);
}
};
var promise: when.Promise<number>;
var foreign = new ForeignPromise<number>(1);
var error = new Error("boom!");
var example: () => void;
var native: Promise<number>;
/* * * * * * *
* Core *
@@ -100,8 +104,16 @@ when.all<number[]>([when(1), when(2), when(3)]).then(results => {
when.map<number[]>([when(1), 2, 3], (num: number, index: number) => num * index).then((results) => {
return results.reduce((r, x) => r + x, 0);
});
when.map<number[]>([when(1), 2, 3], (num: number) => num * num).then((results) => {
return results.reduce((r, x) => r + x, 0);
});
/* when.reduce(arr, reduceFunc, initialValue) */
when.reduce<number>([when(1), 2, 3], (reduction: number, value: number, index: number) => {
return reduction += value * index;
}, 0).then((result: number) => {
return result;
});
when.reduce<number>([when(1), 2, 3], (reduction: number, value: number) => {
return reduction += value;
}, 0).then((result: number) => {
@@ -109,6 +121,12 @@ when.reduce<number>([when(1), 2, 3], (reduction: number, value: number) => {
});
/* when.reduceRight(arr, reduceFunc, initialValue) */
when.reduceRight<number>([when(1), 2, 3], (reduction: number, value: number, index: number) => {
return when(value * index)
.then((v) => reduction += v);
}, 0).then((result: number) => {
return result;
});
when.reduceRight<number>([when(1), 2, 3], (reduction: number, value: number) => {
return when(value)
.then((v) => reduction += v);
@@ -118,7 +136,24 @@ when.reduceRight<number>([when(1), 2, 3], (reduction: number, value: number) =>
/* when.settle(arr) */
when.settle<number>([when(1), when(2), when.reject(new Error("Foo"))]).then(descriptors => {
return descriptors.filter(d => d.state === 'rejected').reduce((r, d) => r + d.value, 0);
return descriptors.reduce((r, d) => {
if (d.state === 'fulfilled') {
return r + d.value;
} else {
console.error(d.reason);
return r;
}
}, 0);
});
when.settle<number>([when(1), when(2), when.reject(new Error("Foo"))]).then(descriptors => {
return descriptors.reduce((r, d) => {
if (d.state === 'rejected') {
console.error(d.reason);
return r;
} else {
return r + d.value;
}
}, 0);
});
/* when.iterate(f, predicate, handler, seed) */
@@ -174,13 +209,16 @@ deferred.reject(error);
when(1).done();
when(1).done((val: number) => console.log(val));
when(1).done(undefined, (err: any) => console.log(err));
when(1).done((val: number) => console.log(val), (err: any) => console.log(err));
/* promise.then(onFulfilled) */
promise = when(1).then();
promise = when(1).then((val: number) => val + val);
promise = when(1).then((val: number) => when(val + val));
promise = when(1).then(undefined, (err: any) => 2);
promise = when(1).then((val: number) => val + val, (err: any) => 2);
promise = when(1).then((val: number) => when(val + val), (err: any) => 2);
@@ -261,6 +299,17 @@ var status: {
status = when(1).inspect()
var status2: when.Snapshot<number>;
status2 = when(1).inspect();
if (status2.state === 'fulfilled') {
console.log(status2.value + 2);
} else if (status2.state === 'rejected') {
console.log(status2.reason);
} else {
console.log(status2.state === 'pending');
}
/* promise.with(thisArg) */
promise = when(1).with(2);
@@ -416,8 +465,8 @@ example = function () {
/* node.liftCallback */
example = function () {
var fetchData: (key: string) => when.Promise<number>;
var handleData: (err: any, result: number) => void;
var fetchData: (key: string) => when.Promise<number> = () => when(1);
var handleData: (err: any, result: number) => void = () => undefined;
var handlePromisedData: (result: when.Promise<number>) => when.Promise<number>;
handlePromisedData = nodefn.liftCallback(handleData);
@@ -428,8 +477,8 @@ example = function () {
/* node.bindCallback */
example = function () {
var fetchData: (key: string) => when.Promise<number>;
var handleData: (err: any, result: number) => void;
var fetchData: (key: string) => when.Promise<number> = () => when(1);
var handleData: (err: any, result: number) => void = () => undefined;
nodefn.bindCallback(fetchData('thing'), handleData);
};
@@ -437,9 +486,16 @@ example = function () {
/* node.createCallback */
example = function () {
when.promise((resolve, reject) =>
when.promise<number>((resolve, reject) =>
nodeFn2(1, '2', nodefn.createCallback({ resolve: resolve, reject: reject })))
.then(
(value: number) => console.log(value),
(err: any) => console.error(err));
};
/* * * * * * * * * * *
* Native Promises *
* * * * * * * * * * */
native = Promise.resolve(when(1));
native = Promise.all([when(1)]).then(([x]) => x);