This repository has been archived by the owner. It is now read-only.

Forward compatible updates for TS 2.4 #342

Merged
merged 3 commits into from Jun 27, 2017
Jump to file or symbol
Failed to load files and symbols.
+246 −112
Diff settings

Always

Just for now

@@ -10,7 +10,7 @@ import '@dojo/shim/Symbol';
* @param iterable The list of objects to iterate over
* @returns {any[]} The list of objects, as an array, with ExtensiblePromises being replaced by Promises.
*/
function unwrapPromises(iterable: Iterable<any> | any[]): any[] {
export function unwrapPromises(iterable: Iterable<any> | any[]): any[] {
const unwrapped: any[] = [];
forOf(iterable, function (item: any): void {
unwrapped.push(item instanceof ExtensiblePromise ? item._promise : item);
@@ -29,24 +29,40 @@ export default class ExtensiblePromise<T> {
/**
* Return a rejected promise wrapped in an ExtensiblePromise
*
* @param {Error?} reason The reason for the rejection
* @returns {ExtensiblePromise}
* @param reason The reason for the rejection
* @returns An extensible promise
*/
static reject<T>(reason?: any): ExtensiblePromise<never>;
/**
* Return a rejected promise wrapped in an ExtensiblePromise
*
* @param reason The reason for the rejection
* @returns An extensible promise
*/
static reject<T>(reason?: Error): any {
return new this<T>((resolve, reject) => reject(reason));
static reject<T>(reason?: any): ExtensiblePromise<T> {
return new this((resolve, reject) => reject(reason));
}
/**
* Return a resolved promise wrapped in an ExtensiblePromise
*
* @param value The value to resolve the promise with
*
* @returns {ExtensiblePromise}
* @returns An extensible promise
*/
static resolve<F extends ExtensiblePromise<void>>(): F;
static resolve<T, F extends ExtensiblePromise<T>>(value: (T | Thenable<T>)): F;
static resolve<T, F extends ExtensiblePromise<T>>(value?: any): F {
return <F> new this<T>((resolve, reject) => resolve(value));
static resolve<P extends ExtensiblePromise<void>>(): P;
/**
* Return a resolved promise wrapped in an ExtensiblePromise
*
* @param value The value to resolve the promise with
*
* @returns An extensible promise
*/
static resolve<T, P extends ExtensiblePromise<T>>(value: T | PromiseLike<T>): P;
static resolve(value?: any | PromiseLike<any>): ExtensiblePromise<any> {
return new this((resolve, reject) => resolve(value));
}
/**
@@ -58,30 +74,78 @@ export default class ExtensiblePromise<T> {
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns {ExtensiblePromise}
* @returns An extensible promise
*/
static all<T>(iterable: DictionaryOfPromises<T>): ExtensiblePromise<{ [key: string]: T }>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: (T | Thenable<T>)[]): ExtensiblePromise<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: T | Thenable<T>): ExtensiblePromise<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: ListOfPromises<T>): ExtensiblePromise<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<F extends ExtensiblePromise<{ [key: string]: T }>, T>(iterable: DictionaryOfPromises<T>): F;
static all<F extends ExtensiblePromise<T[]>, T>(iterable: (T | Thenable<T>)[]): F;
static all<F extends ExtensiblePromise<T[]>, T>(iterable: T | Thenable<T>): F;
static all<F extends ExtensiblePromise<T[]>, T>(iterable: ListOfPromises<T>): F;
static all<F extends ExtensiblePromise<any>, T>(iterable: DictionaryOfPromises<T> | ListOfPromises<T>): F {
static all<T>(iterable: DictionaryOfPromises<T> | ListOfPromises<T>): ExtensiblePromise<T[] | { [key: string]: T }> {
if (!isArrayLike(iterable) && !isIterable(iterable)) {
const promiseKeys = Object.keys(iterable);
return <F> new this((resolve, reject) => {
Promise.all(promiseKeys.map(key => (<DictionaryOfPromises<T>> iterable)[ key ])).then((promiseResults: T[]) => {
const returnValue: {[_: string]: T} = {};
return new this((resolve, reject) => {
Promise.all(promiseKeys.map(key => iterable[key])).then((promiseResults: T[]) => {
const returnValue: { [key: string]: T} = {};
promiseResults.forEach((value: T, index: number) => {
returnValue[ promiseKeys[ index ] ] = value;
returnValue[promiseKeys[index]] = value;
});
resolve(returnValue);
}, reject);
});
}
return <F> new this((resolve, reject) => {
return new this((resolve, reject) => {
Promise.all(unwrapPromises(<Iterable<T>> iterable)).then(resolve, reject);
});
}
@@ -92,8 +156,8 @@ export default class ExtensiblePromise<T> {
* @param iterable An iterable of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns {ExtensiblePromise}
*/
static race<F extends ExtensiblePromise<T>, T>(iterable: Iterable<(T | Thenable<T>)> | (T | Thenable<T>)[]): F {
return <F> new this((resolve, reject) => {
static race<T>(iterable: Iterable<(T | PromiseLike<T>)> | (T | PromiseLike<T>)[]): ExtensiblePromise<T> {
return new this((resolve, reject) => {
Promise.race(unwrapPromises(iterable)).then(resolve, reject);
});
}
@@ -127,9 +191,8 @@ export default class ExtensiblePromise<T> {
*
* @returns {ExtensiblePromise}
*/
catch(onRejected: (reason: Error) => T | Thenable<T> | void): ExtensiblePromise<T>;
catch<U>(onRejected: (reason: Error) => U | Thenable<U>): ExtensiblePromise<U> {
return this.then<U>(undefined, onRejected);
catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): ExtensiblePromise<T | TResult> {
return this.then(undefined, onRejected);
}
/**
@@ -140,16 +203,17 @@ export default class ExtensiblePromise<T> {
*
* @returns {ExtensiblePromise}
*/
then<U, V>(onFulfilled: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected: (reason: Error) => (V | Thenable<V>)): ExtensiblePromise<U | V>;
then<U>(onFulfilled?: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected?: (reason: Error) => void): ExtensiblePromise<U>;
then<U>(onFulfilled?: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected?: (reason: Error) => (U | Thenable<U>)): ExtensiblePromise<U> {
const e: Executor<U> = (resolve, reject) => {
function handler(rejected: boolean, valueOrError: T | U | Error) {
const callback: ((value: T | U | Error) => (U | Thenable<U> | void)) | undefined = rejected ? onRejected : onFulfilled;
then<TResult1 = T, TResult2 = never>(
onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null,
onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2> | void) | undefined | null
): ExtensiblePromise<TResult1 | TResult2> {
const executor: Executor<TResult1> = (resolve, reject) => {
function handler(rejected: boolean, valueOrError: T | TResult1 | Error) {
const callback: ((value: any) => any) | null | undefined = rejected ? onRejected : onFulfilled;
if (typeof callback === 'function') {
try {
resolve(<U> callback(<T> valueOrError));
resolve(callback(valueOrError));
}
catch (error) {
reject(error);
@@ -159,14 +223,14 @@ export default class ExtensiblePromise<T> {
reject(valueOrError);
}
else {
resolve(<U> valueOrError);
resolve(valueOrError as TResult1);
}
}
this._promise.then(handler.bind(null, false), handler.bind(null, true));
};
return new (<{ new(executor: Executor<U>): any }> this.constructor)(e);
return new (this.constructor as typeof ExtensiblePromise)(executor);
}
readonly [Symbol.toStringTag]: 'Promise';
View
@@ -1,6 +1,6 @@
import { Thenable } from '@dojo/shim/interfaces';
import { Executor } from '@dojo/shim/Promise';
import ExtensiblePromise, { ListOfPromises, DictionaryOfPromises } from './ExtensiblePromise';
import ExtensiblePromise, { ListOfPromises, DictionaryOfPromises, unwrapPromises } from './ExtensiblePromise';
import { Iterable } from '@dojo/shim/iterator';
/**
@@ -40,39 +40,116 @@ export default class Task<T> extends ExtensiblePromise<T> {
* @param iterable An iterable of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns {Task}
*/
static race<F extends ExtensiblePromise<T>, T>(iterable: Iterable<(T | Thenable<T>)> | (T | Thenable<T>)[]): Task<T> {
return <Task<T>> super.race(iterable);
static race<T>(iterable: Iterable<(T | Thenable<T>)> | (T | Thenable<T>)[]): Task<T> {
return new this((resolve, reject) => {
Promise.race(unwrapPromises(iterable)).then(resolve, reject);
});
}
/**
* Return a rejected promise wrapped in a Task
*
* @param {Error?} reason The reason for the rejection
* @returns {Task}
* @param reason The reason for the rejection
* @returns A task
*/
static reject<T>(reason?: Error): Task<T> {
return new this<T>((resolve, reject) => reject(reason));
return new this((resolve, reject) => reject(reason));
}
/**
* Return a resolved task.
*
* @param value The value to resolve with
*
* @return {Task}
* @return A task
*/
public static resolve(): Task<void>;
/**
* Return a resolved task.
*
* @param value The value to resolve with
*
* @return A task
*/
public static resolve<T>(value: (T | Thenable<T>)): Task<T>;
/**
* Return a resolved task.
*
* @param value The value to resolve with
*
* @return A task
*/
public static resolve<T>(value?: any): Task<T> {
return new this<T>((resolve, reject) => resolve(value));
}
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: DictionaryOfPromises<T>): Task<{ [key: string]: T }>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: (T | Thenable<T>)[]): Task<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: T | Thenable<T>): Task<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: ListOfPromises<T>): Task<T[]>;
/**
* Return a ExtensiblePromise that resolves when all of the passed in objects have resolved. When used with a key/value
* pair, the returned promise's argument is a key/value pair of the original keys with their resolved values.
*
* @example
* ExtensiblePromise.all({ one: 1, two: 2 }).then(results => console.log(results));
* // { one: 1, two: 2 }
*
* @param iterable An iterable of values to resolve, or a key/value pair of values to resolve. These can be Promises, ExtensiblePromises, or other objects
* @returns An extensible promise
*/
static all<T>(iterable: DictionaryOfPromises<T> | ListOfPromises<T>): Task<any> {
return <Task<T>> super.all(iterable);
return super.all(iterable) as Task<any>;
}
/**
@@ -195,9 +272,8 @@ export default class Task<T> extends ExtensiblePromise<T> {
}
}
catch(onRejected: (reason: Error) => T | Thenable<T> | void): Task<T>;
catch<U>(onRejected: (reason: Error) => U | Thenable<U>): Task<U> {
return this.then(undefined, onRejected);
catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined): Task<T | TResult> {
return this.then(undefined, onRejected) as Task<T | TResult>;
}
/**
@@ -225,18 +301,15 @@ export default class Task<T> extends ExtensiblePromise<T> {
/**
* Adds a callback to be invoked when the Task resolves or is rejected.
*
* @param {Function} onFulfilled A function to call to handle the resolution. The paramter to the function will be the resolved value, if any.
* @param {Function} onRejected A function to call to handle the error. The parameter to the function will be the caught error.
* @param onFulfilled A function to call to handle the resolution. The paramter to the function will be the resolved value, if any.
* @param onRejected A function to call to handle the error. The parameter to the function will be the caught error.
*
* @returns {ExtensiblePromise}
* @returns A task
*/
then<U, V>(onFulfilled: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected: (reason: Error) => (V | Thenable<V>)): Task<U | V>;
then<U>(onFulfilled?: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected?: (reason: Error) => void): Task<U>;
then<U>(onFulfilled?: ((value: T) => (U | Thenable<U> | undefined)) | undefined, onRejected?: (reason: Error) => (U | Thenable<U>)): Task<U>;
then<U>(onFulfilled?: (value?: T) => U | Thenable<U>, onRejected?: (error: Error) => U | Thenable<U>): Task<U> {
then<TResult1 = T, TResult2 = never>(onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): Task<TResult1 | TResult2> {
// FIXME
// tslint:disable-next-line:no-var-keyword
var task = <Task<U>> super.then<U>(
var task = super.then(
// Don't call the onFulfilled or onRejected handlers if this Task is canceled
function (value) {
if (task._state === State.Canceled) {
@@ -256,7 +329,7 @@ export default class Task<T> extends ExtensiblePromise<T> {
}
throw error;
}
);
) as Task<TResult1 | TResult2>;
task.canceler = () => {
// If task's parent (this) hasn't been resolved, cancel it; downward propagation will start at the first
Oops, something went wrong.
ProTip! Use n and p to navigate between commits in a pull request.