Last active
November 20, 2019 23:02
-
-
Save bisubus/96f111cb4a41997bc2ff9a2f1cd1006a to your computer and use it in GitHub Desktop.
Extendable Promise subclass inheritance that works with Babel or TypeScript ES5 target
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// inherits from promise class through the chain | |
new ExtendablePromise(resolve => resolve()).then() instanceof Promise === true | |
// inherits from promise subclass through the chain | |
new ExtendablePromise(resolve => resolve()).then() instanceof ExtendablePromise === true | |
// allows for direct calls for ES5 inheritance | |
ExtendablePromise.call(Object.create(ExtendablePromise.prototype), resolve => resolve()).then() |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class ExtendablePromise { | |
constructor(executor) { | |
if (!(this instanceof ExtendablePromise)) { | |
throw new TypeError("Constructor ExtendablePromise requires 'new'"); | |
} | |
this._promise = new Promise(executor); | |
} | |
catch(onRejected) { | |
return this.constructor.resolve(this._promise.catch(onRejected)); | |
} | |
then(onFulfilled, onRejected) { | |
return this.constructor.resolve(this._promise.then(onFulfilled, onRejected)); | |
} | |
finally(onFinally) { | |
return this.constructor.resolve(this._promise.finally(onFinally)); | |
} | |
} | |
Object.setPrototypeOf(ExtendablePromise, Promise); | |
Object.setPrototypeOf(ExtendablePromise.prototype, Promise.prototype); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Extracted from lib es2015.promise | |
interface ExtendablePromiseConstructor { | |
readonly prototype: ExtendablePromise<any>; | |
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): ExtendablePromise<T>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8]>; | |
all<T1, T2, T3, T4, T5, T6, T7>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7]>; | |
all<T1, T2, T3, T4, T5, T6>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6]>; | |
all<T1, T2, T3, T4, T5>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): ExtendablePromise<[T1, T2, T3, T4, T5]>; | |
all<T1, T2, T3, T4>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): ExtendablePromise<[T1, T2, T3, T4]>; | |
all<T1, T2, T3>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): ExtendablePromise<[T1, T2, T3]>; | |
all<T1, T2>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): ExtendablePromise<[T1, T2]>; | |
all<T>(values: readonly (T | PromiseLike<T>)[]): ExtendablePromise<T[]>; | |
race<T>(values: readonly T[]): ExtendablePromise<T extends PromiseLike<infer U> ? U : T>; | |
race<T>(values: Iterable<T>): ExtendablePromise<T extends PromiseLike<infer U> ? U : T>; | |
reject<T = never>(reason?: any): ExtendablePromise<T>; | |
resolve<T>(value: T | PromiseLike<T>): ExtendablePromise<T>; | |
resolve(): ExtendablePromise<void>; | |
} | |
class ExtendablePromise<T> { | |
static all: ExtendablePromiseConstructor['all']; | |
static race: ExtendablePromiseConstructor['race']; | |
static reject: ExtendablePromiseConstructor['reject']; | |
static resolve: ExtendablePromiseConstructor['resolve']; | |
[Symbol.toStringTag]: string; | |
protected _promise: Promise<T>; | |
constructor(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) { | |
if (!(this instanceof ExtendablePromise)) { | |
throw new TypeError("Constructor ExtendablePromise requires 'new'"); | |
} | |
this._promise = new Promise<T>(executor); | |
} | |
catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): ExtendablePromise<T | TResult> { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.catch(onRejected) | |
); | |
} | |
then<TResult1 = T, TResult2 = never>(onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): ExtendablePromise<TResult1 | TResult2> { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.then(onFulfilled, onRejected) | |
); | |
} | |
finally(onFinally?: (() => void) | undefined | null): ExtendablePromise<T> { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.finally(onFinally) | |
); | |
} | |
} | |
Object.setPrototypeOf(ExtendablePromise, Promise); | |
Object.setPrototypeOf(ExtendablePromise.prototype, Promise.prototype); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
var ExtendablePromise = function ExtendablePromise(executor) { | |
if (!(this instanceof ExtendablePromise)) { | |
throw new TypeError("Constructor ExtendablePromise requires 'new'"); | |
} | |
this._promise = new Promise(executor); | |
return this; | |
} | |
Object.getOwnPropertyNames(Promise).forEach(function (key) { | |
if (typeof Promise[key] === 'function') { | |
ExtendablePromise[key] = Promise[key]; | |
} | |
}); | |
ExtendablePromise.prototype = Object.create(Promise.prototype); | |
ExtendablePromise.prototype.constructor = ExtendablePromise; | |
ExtendablePromise.prototype.catch = function catch_(onRejected) { | |
return this.constructor.resolve(this._promise.catch(onRejected)); | |
}; | |
ExtendablePromise.prototype.then = function then(onFulfilled, onRejected) { | |
return this.constructor.resolve(this._promise.then(onFulfilled, onRejected)); | |
}; | |
ExtendablePromise.prototype.finally = function finally_(onFinally) { | |
return this.constructor.resolve(this._promise.finally(onFinally)); | |
}; |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// Extracted from lib es2015.promise | |
interface ExtendablePromiseConstructor { | |
prototype: ExtendablePromise<any>; | |
new <T>(executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void): ExtendablePromise<T>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8, T9, T10>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>, T10 | PromiseLike<T10>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9, T10]>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8, T9>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>, T9 | PromiseLike<T9>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8, T9]>; | |
all<T1, T2, T3, T4, T5, T6, T7, T8>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>, T8 | PromiseLike<T8>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7, T8]>; | |
all<T1, T2, T3, T4, T5, T6, T7>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>, T7 | PromiseLike<T7>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6, T7]>; | |
all<T1, T2, T3, T4, T5, T6>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>, T6 | PromiseLike<T6>]): ExtendablePromise<[T1, T2, T3, T4, T5, T6]>; | |
all<T1, T2, T3, T4, T5>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>, T5 | PromiseLike<T5>]): ExtendablePromise<[T1, T2, T3, T4, T5]>; | |
all<T1, T2, T3, T4>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>, T4 | PromiseLike <T4>]): ExtendablePromise<[T1, T2, T3, T4]>; | |
all<T1, T2, T3>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>, T3 | PromiseLike<T3>]): ExtendablePromise<[T1, T2, T3]>; | |
all<T1, T2>(values: readonly [T1 | PromiseLike<T1>, T2 | PromiseLike<T2>]): ExtendablePromise<[T1, T2]>; | |
all<T>(values: readonly (T | PromiseLike<T>)[]): ExtendablePromise<T[]>; | |
race<T>(values: readonly T[]): ExtendablePromise<T extends PromiseLike<infer U> ? U : T>; | |
race<T>(values: Iterable<T>): ExtendablePromise<T extends PromiseLike<infer U> ? U : T>; | |
reject<T = never>(reason?: any): ExtendablePromise<T>; | |
resolve<T>(value: T | PromiseLike<T>): ExtendablePromise<T>; | |
resolve(): ExtendablePromise<void>; | |
} | |
interface ExtendablePromise<T> { | |
_promise: Promise<T>; | |
[Symbol.toStringTag]: string; | |
catch<TResult = never>(onRejected?: ((reason: any) => TResult | PromiseLike<TResult>) | undefined | null): ExtendablePromise<T | TResult>; | |
then<TResult1 = T, TResult2 = never>(onFulfilled?: ((value: T) => TResult1 | PromiseLike<TResult1>) | undefined | null, onRejected?: ((reason: any) => TResult2 | PromiseLike<TResult2>) | undefined | null): ExtendablePromise<TResult1 | TResult2>; | |
finally(onFinally?: (() => void) | undefined | null): ExtendablePromise<T>; | |
} | |
var ExtendablePromise = function ExtendablePromise<T>(this: ExtendablePromise<T>, executor: (resolve: (value?: T | PromiseLike<T>) => void, reject: (reason?: any) => void) => void) { | |
if (!(this instanceof ExtendablePromise)) { | |
throw new TypeError("Constructor ExtendablePromise requires 'new'"); | |
} | |
this._promise = new Promise(executor); | |
return this; | |
} as unknown as ExtendablePromiseConstructor; | |
type TExtendablePromiseMethods = keyof ExtendablePromiseConstructor; | |
(Object.getOwnPropertyNames(Promise) as (keyof ExtendablePromiseConstructor)[]) | |
.forEach(function (key) { | |
if (typeof Promise[key] === 'function') { | |
ExtendablePromise[key] = Promise[key] as any; | |
} | |
}); | |
ExtendablePromise.prototype = Object.create(Promise.prototype); | |
ExtendablePromise.prototype.constructor = ExtendablePromise; | |
ExtendablePromise.prototype.catch = function catch_(onRejected) { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.catch(onRejected) | |
); | |
}; | |
ExtendablePromise.prototype.then = function then(onFulfilled, onRejected) { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.then(onFulfilled, onRejected) | |
); | |
}; | |
ExtendablePromise.prototype.finally = function finally_(onFinally) { | |
return (this.constructor as ExtendablePromiseConstructor).resolve( | |
this._promise.finally(onFinally) | |
); | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment