/**
 * TypeScript version of @istarkov's cancellable Promise wrapper.
 *
 * @see https://github.com/facebook/react/issues/5465#issuecomment-157888325
 */
const makeCancelable = <T>(promise: Promise<T>): { promise: Promise<T>; cancel(): void } => {
  let hasCanceled = false;

  const wrappedPromise = new Promise<T>((resolve, reject) => {
    promise.then(
      value => hasCanceled
        ? reject({ isCanceled: true })
        : resolve(value),
      error => hasCanceled
        ? reject({ isCanceled: true })
        : reject(error),
    );
  });

  return {
    promise: wrappedPromise,
    cancel(): void {
      hasCanceled = true;
    },
  };
};

const somePromise = new Promise(resolve => setTimeout(resolve, 1000));
const cancelable = makeCancelable(somePromise);

cancelable.promise
  .then(console.log)
  .catch(({ isCanceled }) => console.error('isCanceled', isCanceled));

cancelable.cancel();