From 0adc6614cb35a8b247eee0a059f8a26c7d523092 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 30 Nov 2014 16:14:41 +1300 Subject: [PATCH 1/5] Add tests for when's Core and Promises API --- when/when-tests.ts | 184 +++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 184 insertions(+) create mode 100644 when/when-tests.ts diff --git a/when/when-tests.ts b/when/when-tests.ts new file mode 100644 index 0000000000..35a97e01e8 --- /dev/null +++ b/when/when-tests.ts @@ -0,0 +1,184 @@ +/// + +import when = require("when"); + +class ForeignPromise { + constructor(private value: T) { + } + + then(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U) { return new ForeignPromise(onFulfilled(this.value)); } +}; + +var promise: when.Promise; +var foreign = new ForeignPromise(1); +var error = new Error("boom!"); + +// TODO: with TypeScript 1.4 a lot of these functions should change to use PromiseOrValue +// type PromiseOrValue = Promise | T; + +/* * * * * * * + * Core * + * * * * * * */ + +/* when(x) */ + +promise = when(1); +promise = when(when(1)); +promise = when(foreign); + +/* when(x, f) */ + +promise = when(1, val => val + val); +promise = when(when(1), val => val + val); +promise = when(foreign, val => val + val); + +/* when.try(f, ...args) */ + +promise = when.attempt(() => 1); + +promise = when.attempt((a: number) => a + a, 1); +promise = when.attempt((a: number) => a + a, when(1)); + +promise = when.attempt((a: number, b: number) => a + b, 1, 2); +promise = when.attempt((a: number, b: number) => a + b, 1, when(2)); +promise = when.attempt((a: number, b: number) => a + b, when(1), 2); +promise = when.attempt((a: number, b: number) => a + b, when(1), when(2)); + +promise = when.attempt((a: number, b: number, c: number) => a + b + c, 1, 2, 3); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, 1, when(2), 3); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, when(1), 2, 3); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, when(1), when(2), 3); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, 1, 2, when(3)); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, 1, when(2), when(3)); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, when(1), 2, when(3)); +promise = when.attempt((a: number, b: number, c: number) => a + b + c, when(1), when(2), when(3)); + +/* when.lift(f) */ + +// TODO: This is the major issue with lack of union types, it's not possible to represent the return type of when.lift without them. + +var liftedFunc0: () => when.Promise = when.lift(() => 2); +var liftedFunc1: (a: when.Promise) => when.Promise = when.lift((a: number) => a + a); +var liftedFunc2: (a: when.Promise, b: when.Promise) => when.Promise = when.lift((a: number, b: number) => a + b); +var liftedFunc3: (a: when.Promise, b: when.Promise, c: when.Promise) => when.Promise = when.lift((a: number, b: number, c: number) => a + b + c); + +/* when.join(...promises) */ + +var joinedPromise: when.Promise = when.join(when(1), when(2), when(3)); + +/* when.promise(resolver) */ + +promise = when.promise(resolve => resolve(5)); +promise = when.promise((resolve, reject) => reject(error)); + +/* when.resolve(x) */ + +promise = when.resolve(1); +promise = when.resolve(promise); +promise = when.resolve(foreign); + +/* when.reject(error) */ + +promise = when.reject(error); + +/* when.defer() */ + +var deferred = when.defer(); +promise = deferred.promise; +deferred.resolve(1); +deferred.reject(error); + +/* * * * * * * * + * Promise * + * * * * * * * */ + +/* promise.done(handleResult, handleError) */ + +when(1).done((val: number) => console.log(val)); +when(1).done((val: number) => console.log(val), (err: any) => console.log(err)); + +/* promise.then(onFulfilled) */ + +promise = when(1).then((val: number) => val + val); +promise = when(1).then((val: number) => when(val + val)); + +promise = when(1).then((val: number) => val + val, (err: any) => 2); +promise = when(1).then((val: number) => when(val + val), (err: any) => 2); + +/* promise.spread(onFulfilledArray) */ + +// TODO: Work out how to do this... +// promise = when([1, 2, 3]).spread((a: number, b: number) => a + b); +// promise = when([1, 2, 3]).spread((a: number, b: number) => when(a + b)); + +/* promise.fold(combine, promise2) */ + +promise = when(1).fold((a: number, b: number) => a + b, 2); +promise = when(1).fold((a: number, b: number) => a + b, when(2)); + +promise = when(1).fold((a: number, b: number) => when(a + b), 2); +promise = when(1).fold((a: number, b: number) => when(a + b), when(2)); + +/* promise.catch(onRejected) */ + +promise = when(1).catch((err: any) => 2); +promise = when(1).catch((err: any) => when(2)); + +promise = when(1).catch((err: any) => err.good, (err: any) => 2); +promise = when(1).catch((err: any) => err.good, (err: any) => when(2)); + +//TODO: error constructor predicate + +promise = when(1).otherwise((err: any) => 2); +promise = when(1).otherwise((err: any) => when(2)); + +promise = when(1).otherwise((err: any) => err.good, (err: any) => 2); +promise = when(1).otherwise((err: any) => err.good, (err: any) => when(2)); + +/* promise.finally(cleanup) */ + +promise = when(1).finally(() => console.log('Cleaning up')); + +promise = when(1).ensure(() => console.log('Cleaning up')); + +/* promise.yield(x) */ + +promise = when(true).yield(1); +promise = when(true).yield(when(2)); + +/* promise.else(x) */ + +promise = when(1).else(2); +promise = when(1).else(2); + +promise = when(1).orElse(2); +promise = when(1).orElse(2); + +/* promise.tap(onFulfilledSideEffect) */ + +promise = when(1).tap(val => console.log(val)); + +/* promise.delay(milliseconds) */ + +promise = when(1).delay(1000); + +/* promise.timeout(milliseconds, reason) */ + +promise = when(1).timeout(1000); +promise = when(1).timeout(1000, new Error('Too SLOW!')); + +/* promise.inspect() */ + +var status: { + state: string; + value?: number; + reason?: any; +}; + +status = when(1).inspect() + +/* promise.with(thisArg) */ + +promise = when(1).with(2); + +promise = when(1).withThis(2); From d72601e3208bc02a86dd29050c6bdb6ec1fc064c Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 30 Nov 2014 16:17:18 +1300 Subject: [PATCH 2/5] Add when(x) overloads --- when/when.d.ts | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/when/when.d.ts b/when/when.d.ts index 475fb23a6e..a9e9d483db 100644 --- a/when/when.d.ts +++ b/when/when.d.ts @@ -3,6 +3,10 @@ // Definitions by: Derek Cicerone // Definitions: https://github.com/borisyankov/DefinitelyTyped +declare function When(value: When.Promise): When.Promise; +declare function When(value: When.Thenable): When.Promise; +declare function When(value: T): When.Promise; + declare module When { /** @@ -80,6 +84,10 @@ declare module When { then(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U, onProgress?: (update: any) => void): Promise; } + interface Thenable { + then(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U): Thenable; + } + interface Snapshot { state: string; value?: T; From afce6f14e4388b7c40eb8e9a7867a6c8724a0ac5 Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 30 Nov 2014 16:18:50 +1300 Subject: [PATCH 3/5] Add when(x, f) overloads --- when/when.d.ts | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/when/when.d.ts b/when/when.d.ts index a9e9d483db..c90478c109 100644 --- a/when/when.d.ts +++ b/when/when.d.ts @@ -7,6 +7,10 @@ declare function When(value: When.Promise): When.Promise; declare function When(value: When.Thenable): When.Promise; declare function When(value: T): When.Promise; +declare function When(value: When.Promise, transform: (val: T) => U): When.Promise; +declare function When(value: When.Thenable, transform: (val: T) => U): When.Promise; +declare function When(value: T, transform: (val: T) => U): When.Promise; + declare module When { /** From 11f556cc22a8283ac649b2965b0472fecb8d413e Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 30 Nov 2014 16:36:16 +1300 Subject: [PATCH 4/5] Add overloads for when's members --- when/when.d.ts | 28 ++++++++++++++++++++++++++++ 1 file changed, 28 insertions(+) diff --git a/when/when.d.ts b/when/when.d.ts index c90478c109..62d2cfa0dd 100644 --- a/when/when.d.ts +++ b/when/when.d.ts @@ -12,6 +12,33 @@ declare function When(value: When.Thenable, transform: (val: T) => U): declare function When(value: T, transform: (val: T) => U): When.Promise; declare module When { + function attempt(f: () => T): Promise; + + function attempt(f: (a: A) => T, a: Promise): Promise; + function attempt(f: (a: A) => T, a: A): Promise; + + function attempt(f: (a: A, b: B) => T, a: Promise, b: Promise): Promise; + function attempt(f: (a: A, b: B) => T, a: Promise, b: B): Promise; + function attempt(f: (a: A, b: B) => T, a: A, b: Promise): Promise; + function attempt(f: (a: A, b: B) => T, a: A, b: B): Promise; + + function attempt(f: (a: A, b: B, c: C) => T, a: Promise, b: Promise, c: Promise): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: Promise, b: Promise, c: C): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: Promise, b: B, c: Promise): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: Promise, b: B, c: C): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: A, b: Promise, c: Promise): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: A, b: Promise, c: C): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: A, b: B, c: Promise): Promise; + function attempt(f: (a: A, b: B, c: C) => T, a: A, b: B, c: C): Promise; + + function lift(f: () => T): () => Promise; + function lift(f: (a: A) => T): (a: Promise) => Promise; + function lift(f: (a: A, b: B) => T): (a: Promise, b: Promise) => Promise; + function lift(f: (a: A, b: B, c: C) => T): (a: Promise, b: Promise, c: Promise) => Promise; + + function promise(resolver: (resolve: (value: T) => void, reject: (reason: any) => void) => void): Promise; + + function reject(reason: any): Promise; /** * Return a promise that will resolve only once all the supplied promisesOrValues @@ -53,6 +80,7 @@ declare module When { * - rejected with promiseOrValue's reason after it is rejected */ function resolve(promise: Promise): Promise; + function resolve(foreign: Thenable): Promise; function resolve(value?: T): Promise; interface Deferred { From aa5d16d071eb0b979560930bd2cf02c81eb03aac Mon Sep 17 00:00:00 2001 From: Wim Looman Date: Sun, 30 Nov 2014 16:49:18 +1300 Subject: [PATCH 5/5] Add when.Promise members --- when/when.d.ts | 43 ++++++++++++++++++++++++++++++++++++++----- 1 file changed, 38 insertions(+), 5 deletions(-) diff --git a/when/when.d.ts b/when/when.d.ts index 62d2cfa0dd..1f71d9ebbd 100644 --- a/when/when.d.ts +++ b/when/when.d.ts @@ -92,28 +92,61 @@ declare module When { } interface Promise { + catch(onRejected?: (reason: any) => Promise): Promise; + catch(onRejected?: (reason: any) => U): Promise; + + catch(filter: (reason: any) => boolean, onRejected?: (reason: any) => Promise): Promise; + catch(filter: (reason: any) => boolean, onRejected?: (reason: any) => U): Promise; + // Make sure you test any usage of these overloads, exceptionType must // be a constructor with prototype set to an instance of Error. catch(exceptionType: any, onRejected?: (reason: any) => Promise): Promise; catch(exceptionType: any, onRejected?: (reason: any) => U): Promise; - catch(filter: (reason: any) => boolean, onRejected?: (reason: any) => Promise): Promise; - catch(filter: (reason: any) => boolean, onRejected?: (reason: any) => U): Promise; - - catch(onRejected?: (reason: any) => Promise): Promise; - catch(onRejected?: (reason: any) => U): Promise; + finally(onFulfilledOrRejected: Function): Promise; ensure(onFulfilledOrRejected: Function): Promise; inspect(): Snapshot; + yield(value: Promise): Promise; + yield(value: U): Promise; + + else(value: T): Promise; + orElse(value: T): Promise; + + tap(onFulfilledSideEffect: (value: T) => void): Promise; + + delay(milliseconds: number): Promise; + + timeout(milliseconds: number, reason?: any): Promise; + + with(thisArg: any): Promise; + withThis(thisArg: any): Promise; + otherwise(onRejected?: (reason: any) => Promise): Promise; otherwise(onRejected?: (reason: any) => U): Promise; + otherwise(predicate: (reason: any) => boolean, onRejected?: (reason: any) => Promise): Promise; + otherwise(predicate: (reason: any) => boolean, onRejected?: (reason: any) => U): Promise; + + // Make sure you test any usage of these overloads, exceptionType must + // be a constructor with prototype set to an instance of Error. + otherwise(exceptionType: any, onRejected?: (reason: any) => Promise): Promise; + otherwise(exceptionType: any, onRejected?: (reason: any) => U): Promise; + then(onFulfilled: (value: T) => Promise, onRejected?: (reason: any) => Promise, onProgress?: (update: any) => void): Promise; then(onFulfilled: (value: T) => Promise, onRejected?: (reason: any) => U, onProgress?: (update: any) => void): Promise; then(onFulfilled: (value: T) => U, onRejected?: (reason: any) => Promise, onProgress?: (update: any) => void): Promise; then(onFulfilled: (value: T) => U, onRejected?: (reason: any) => U, onProgress?: (update: any) => void): Promise; + + done(onFulfilled: (value: T) => void, onRejected?: (reason: any) => void): void; + + fold(combine: (value1: T, value2: V) => Promise, value2: V): Promise; + fold(combine: (value1: T, value2: V) => Promise, value2: Promise): Promise; + + fold(combine: (value1: T, value2: V) => U, value2: V): Promise; + fold(combine: (value1: T, value2: V) => U, value2: Promise): Promise; } interface Thenable {