Repository: true-myth/true-myth
Pull request #921 (2025-01-11 19:44:04)

v9.0: remove deprecated code
Note: landing this on `main` does not oblige us *not* to make further releases (e.g. bug fixes) against v8.x. We will just need to do like we did for the v5.x series: make an 8.x release branch to keep working against if that comes up!


Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 8b546f9..2ec058b 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -12,25 +12,6 @@ The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) a
 
 
 
-
-## 8.4.0 (2025-01-11)
-
-Highlight: adds auto-curried, module-scope versions of all the `Task` instance methods like `map` and `andThen` and more. Hot on the heels of 8.3.0, with what we *think* is probably the last set of features for this release!
-
-#### (:rocket: Enhancement)
-* [#918](https://github.com/true-myth/true-myth/pull/918) Task: module-scoped versions of instance methods ([@chriskrycho](https://github.com/chriskrycho))
-
-#### (:memo: Documentation)
-* [#920](https://github.com/true-myth/true-myth/pull/920) docs: clarify tips aboout auto-curried forms ([@chriskrycho](https://github.com/chriskrycho))
-* [#919](https://github.com/true-myth/true-myth/pull/919) docs: add many type parameter docs ([@chriskrycho](https://github.com/chriskrycho))
-
-#### (:house: Internal)
-* [#917](https://github.com/true-myth/true-myth/pull/917) internal: clean up a `console.log` ([@chriskrycho](https://github.com/chriskrycho))
-
-#### Committers: 1
-- Chris Krycho ([@chriskrycho](https://github.com/chriskrycho))
-
-
 ## 8.3.0 (2025-01-10)
 
 Highlights:
diff --git a/package.json b/package.json
index 11b9909..2bb097d 100644
--- a/package.json
+++ b/package.json
@@ -19,7 +19,7 @@
   "bugs": {
     "url": "https://github.com/true-myth/true-myth/issues"
   },
-  "version": "8.4.0",
+  "version": "8.3.0",
   "type": "module",
   "main": "dist/es/index.js",
   "module": "dist/es/index.js",
diff --git a/src/maybe.ts b/src/maybe.ts
index 61ce63c..e3cef24 100644
--- a/src/maybe.ts
+++ b/src/maybe.ts
@@ -1553,13 +1553,6 @@ export function safe<
   return (...params) => Maybe.of(fn(...params) as R);
 }
 
-/**
-  @alias for {@linkcode safe}.
-  @deprecated Switch to using {@linkcode safe} instead. This will be removed at
-    9.0.
- */
-export const wrapReturn = safe;
-
 /**
   The public interface for the {@linkcode Maybe} class *as a value*: a
   constructor and the associated static properties.
diff --git a/src/task.ts b/src/task.ts
index 0163050..0b00bcf 100644
--- a/src/task.ts
+++ b/src/task.ts
@@ -62,112 +62,6 @@ class TaskImpl<T, E> implements PromiseLike<Result<T, E>> {
     }
   }
 
-  /**
-    Produce a `Task<T, E>` from a promise of a {@linkcode Result Result<T, E>}.
-
-    > [!WARNING]
-    > This constructor assumes you have already correctly handled the promise
-    > rejection state, presumably by mapping it into the wrapped `Result`. It is
-    > *unsafe* for this promise ever to reject! You should only ever use this
-    > with `Promise<Result<T, E>>` you have created yourself (including via a
-    > `Task`, of course).
-    >
-    > For any other `Promise<Result<T, E>>`, you should first attach a `catch`
-    > handler which will also produce a `Result<T, E>`.
-    >
-    > If you call this with an unmanaged `Promise<Result<T, E>>`, that is, one
-    > that has *not* correctly set up a `catch` handler, the rejection will
-    > throw an {@linkcode UnsafePromise} error that will ***not*** be catchable
-    > by awaiting the `Task` or its original `Promise`. This can cause test
-    > instability and unpredictable behavior in your application.
-
-    @param promise The promise from which to create the `Task`.
-
-    @group Constructors
-
-    @deprecated Use the module-scoped {@linkcode fromUnsafePromise} instead.
-   */
-  static fromUnsafePromise<T, E>(promise: Promise<Result<T, E>>): Task<T, E> {
-    return new Task((resolve, reject) => {
-      promise.then(
-        matchResult({
-          Ok: resolve,
-          Err: reject,
-        }),
-        (rejectionReason: unknown) => {
-          throw new UnsafePromise(rejectionReason);
-        }
-      );
-    });
-  }
-
-  /**
-    Produce a `Task<T, unknown>` from a promise.
-
-    To handle the error case and produce a concrete `Task<T, E>` instead, use
-    the overload which accepts an `onRejection` handler instead.
-
-    @param promise The promise from which to create the `Task`.
-
-    @group Constructors
-
-    @deprecated This will be removed at 9.0. Switch to the module-scoped
-      function {@linkcode fromPromise}.
-   */
-  static try<T>(promise: Promise<T>): Task<T, unknown> {
-    return new Task((resolve, reject) => {
-      promise.then(resolve, reject);
-    });
-  }
-
-  /**
-    Produce a {@linkcode Task Task<T, E>} from a `Promise<T>` and use a fallback
-    value if the task rejects, ignoring the rejection reason.
-
-    Notes:
-
-    - To leave any error as `unknown`, use the overload which accepts only the
-      promise.
-    - To handle the rejection reason rather than ignoring it, use the overload
-      which accepts a function.
-
-    @param promise The promise from which to create the `Task`.
-    @param rejectionValue A function to transform an unknown rejection reason
-      into a known `E`.
-
-    @group Constructors
-
-    @deprecated This will be removed at 9.0. Switch to the module-level function
-      {@linkcode safelyTryOr}, which accepts a callback instead.
-   */
-  static tryOr<T, E>(promise: Promise<T>, rejectionValue: E): Task<T, E> {
-    return new Task((resolve, reject) => {
-      promise.then(resolve, (_reason) => reject(rejectionValue));
-    });
-  }
-
-  /**
-    Produce a `Task<T, E>` from a `Promise<T>` and a function to transform an
-    unknown error to `E`.
-
-    To leave any error as `unknown`, use the overload which accepts only the
-    promise.
-
-    @param promise The promise from which to create the `Task`.
-    @param onRejection A function to transform an unknown rejection reason into
-      a known `E`.
-
-    @group Constructors
-
-    @deprecated This will be removed at 9.0. Switch to the module-level function
-      {@linkcode safelyTryOrElse}, which accepts a callback instead.
-   */
-  static tryOrElse<T, E>(promise: Promise<T>, onRejection: (reason: unknown) => E): Task<T, E> {
-    return new Task((resolve, reject) => {
-      promise.then(resolve, (reason) => reject(onRejection(reason)));
-    });
-  }
-
   /**
     Construct a `Task` which is already resolved. Useful when you have a value
     already, but need it to be available in an API which expects a `Task`.
@@ -220,20 +114,6 @@ class TaskImpl<T, E> implements PromiseLike<Result<T, E>> {
     return new Task((_, reject) => reject(result));
   }
 
-  /**
-    Build a {@linkcode Task Task<T, E>} from a {@linkcode Result Result<T, E>}.
-
-    @deprecated Use the module-scoped {@linkcode fromResult} instead.
-   */
-  static fromResult<T, E>(result: Result<T, E>): Task<T, E> {
-    return new Task((resolve, reject) =>
-      result.match({
-        Ok: resolve,
-        Err: reject,
-      })
-    );
-  }
-
   /**
     Create a pending `Task` and supply `resolveWith` and `rejectWith` helpers,
     similar to the [`Promise.withResolvers`][pwr] static method, but producing a
@@ -378,7 +258,7 @@ class TaskImpl<T, E> implements PromiseLike<Result<T, E>> {
       it is `Resolved`.
    */
   map<U>(mapFn: (t: T) => U): Task<U, E> {
-    return Task.fromUnsafePromise(this.#promise.then(mapResult(mapFn)));
+    return fromUnsafePromise(this.#promise.then(mapResult(mapFn)));
   }
 
   /**
@@ -414,7 +294,7 @@ class TaskImpl<T, E> implements PromiseLike<Result<T, E>> {
       rejected.
    */
   mapRejected<F>(mapFn: (e: E) => F): Task<T, F> {
-    return TaskImpl.fromUnsafePromise(this.#promise.then(mapErr(mapFn)));
+    return fromUnsafePromise(this.#promise.then(mapErr(mapFn)));
   }
 
   /**
@@ -1242,12 +1122,6 @@ export class InvalidAccess extends Error {
   }
 }
 
-/** @inheritdoc Task.tryOr */
-export const tryOr = TaskImpl.tryOr;
-
-/** @inheritdoc Task.tryOrElse */
-export const tryOrElse = TaskImpl.tryOrElse;
-
 /* v8 ignore next 3 */
 function unreachable(value: never): never {
   throw new Error(`Unexpected value: ${value}`);
@@ -1274,8 +1148,8 @@ export interface TaskConstructor extends Omit<typeof TaskImpl, 'constructor'> {
 
     - {@linkcode fromPromise}
     - {@linkcode safelyTry}
-    - {@linkcode safelyTryOr}
-    - {@linkcode safelyTryOrElse}
+    - {@linkcode tryOr}
+    - {@linkcode tryOrElse}
 
     For constructing a `Task` immediately resolved or rejected with given
     values, see {@linkcode Task.resolve} and {@linkcode Task.reject}
@@ -1400,8 +1274,8 @@ export const withResolvers = Task.withResolvers;
   > [!IMPORTANT]
   > This does not (and by definition cannot) handle errors that happen during
   > construction of the `Promise`, because those happen before this is called.
-  > See {@linkcode safelyTry}, {@linkcode safelyTryOr}, or
-  > {@linkcode safelyTryOrElse} for alternatives which accept a callback for
+  > See {@linkcode safelyTry}, {@linkcode tryOr}, or
+  > {@linkcode tryOrElse} for alternatives which accept a callback for
   > constructing a promise and can therefore handle errors thrown in the call.
 
   @param promise The promise from which to create the `Task`.
@@ -1424,8 +1298,8 @@ export function fromPromise<T>(promise: Promise<T>): Task<T, unknown>;
   > [!IMPORTANT]
   > This does not (and by definition cannot) handle errors that happen during
   > construction of the `Promise`, because those happen before this is called.
-  > See {@linkcode safelyTry}, {@linkcode safelyTryOr}, or
-  > {@linkcode safelyTryOrElse} for alternatives which accept a callback for
+  > See {@linkcode safelyTry}, {@linkcode tryOr}, or
+  > {@linkcode tryOrElse} for alternatives which accept a callback for
   > constructing a promise and can therefore handle errors thrown in the call.
 
   @param promise The promise from which to create the `Task`.
@@ -1635,9 +1509,9 @@ export function safelyTry<T>(fn: () => Promise<T>): Task<T, unknown> {
     rejects with the rejection value of the promise *or* any error thrown while
     invoking `fn`.
 */
-export function safelyTryOr<T, E>(rejection: E, fn: () => Promise<T>): Task<T, E>;
-export function safelyTryOr<T, E>(rejection: E): (fn: () => Promise<T>) => Task<T, E>;
-export function safelyTryOr<T, E>(
+export function tryOr<T, E>(rejection: E, fn: () => Promise<T>): Task<T, E>;
+export function tryOr<T, E>(rejection: E): (fn: () => Promise<T>) => Task<T, E>;
+export function tryOr<T, E>(
   rejection: E,
   fn?: () => Promise<T>
 ): Task<T, E> | ((fn: () => Promise<T>) => Task<T, E>) {
@@ -1653,6 +1527,24 @@ export function safelyTryOr<T, E>(
   return curry1(op, fn);
 }
 
+/**
+  An alias for {@linkcode tryOr} for ease of migrating from v8.x to v9.x.
+
+  > [!TIP]
+  > You should switch to {@linkcode tryOr}. We expect to deprecate and remove
+  > this alias at some point!
+*/
+export const safelyTryOr = tryOr;
+
+/**
+  An alias for {@linkcode tryOrElse} for ease of migrating from v8.x to v9.x.
+
+  > [!TIP]
+  > You should switch to {@linkcode tryOrElse}. We expect to deprecate and
+  > remove this alias at some point!
+*/
+export const safelyTryOrElse = tryOrElse;
+
 /**
   Given a function which takes no arguments and returns a `Promise` and a
   function which accepts an `unknown` rejection reason and transforms it into a
@@ -1707,14 +1599,11 @@ export function safelyTryOr<T, E>(
     rejects with the rejection value of the promise *or* any error thrown while
     invoking `fn`.
 */
-export function safelyTryOrElse<T, E>(
-  onError: (reason: unknown) => E,
-  fn: () => Promise<T>
-): Task<T, E>;
-export function safelyTryOrElse<T, E>(
+export function tryOrElse<T, E>(onError: (reason: unknown) => E, fn: () => Promise<T>): Task<T, E>;
+export function tryOrElse<T, E>(
   onError: (reason: unknown) => E
 ): (fn: () => Promise<T>) => Task<T, E>;
-export function safelyTryOrElse<T, E>(
+export function tryOrElse<T, E>(
   onError: (reason: unknown) => E,
   fn?: () => Promise<T>
 ): Task<T, E> | ((fn: () => Promise<T>) => Task<T, E>) {
@@ -1813,7 +1702,7 @@ export function safe<
   E,
 >(fn: F, onError?: (reason: unknown) => E): (...params: P) => Task<R, unknown> {
   let handleError = onError ?? identity;
-  return (...params) => safelyTryOrElse(handleError, () => fn(...params) as R);
+  return (...params) => tryOrElse(handleError, () => fn(...params) as R);
 }
 
 /**
@@ -1906,7 +1795,7 @@ export function safeNullable<
 >(fn: F, onError?: (reason: unknown) => E): (...params: P) => Task<Maybe<NonNullable<R>>, unknown> {
   let handleError = onError ?? identity;
   return (...params) =>
-    safelyTryOrElse(handleError, async () => {
+    tryOrElse(handleError, async () => {
       let theValue = (await fn(...params)) as R;
       return Maybe.of(theValue) as Maybe<NonNullable<R>>;
     });
@@ -2133,7 +2022,7 @@ export function timeout<T, E>(
 }
 
 /**
-  Standalone version of {@linkcode Task.toPromise Task.prototype.toPromise}.  
+  Standalone version of {@linkcode Task.toPromise Task.prototype.toPromise}.
 
   @template T The type of the value when the `Task` resolves successfully.
   @template E The type of the rejection reason when the `Task` rejects.


Test patch:
diff --git a/test/maybe.test.ts b/test/maybe.test.ts
index 01a71da..1d3612f 100644
--- a/test/maybe.test.ts
+++ b/test/maybe.test.ts
@@ -551,31 +551,6 @@ describe('`Maybe` pure functions', () => {
     expectTypeOf(querySelector).toEqualTypeOf<() => Maybe<string>>();
   });
 
-  test('`wrapReturn`', () => {
-    const empty = '';
-    const emptyResult = MaybeNS.nothing();
-
-    const full = 'hello';
-    const fullResult = MaybeNS.just(full.length);
-
-    const mayBeNull = (s: string): number | null => (s.length > 0 ? s.length : null);
-    const mayNotBeNull = MaybeNS.wrapReturn(mayBeNull);
-
-    expect(mayNotBeNull(empty)).toEqual(emptyResult);
-    expect(mayNotBeNull(full)).toEqual(fullResult);
-
-    const mayBeUndefined = (s: string): number | undefined => (s.length > 0 ? s.length : undefined);
-    const mayNotBeUndefined = MaybeNS.wrapReturn(mayBeUndefined);
-
-    expect(mayNotBeUndefined(empty)).toEqual(emptyResult);
-    expect(mayNotBeUndefined(full)).toEqual(fullResult);
-
-    const returnsNullable = (): string | null => null;
-
-    const querySelector = MaybeNS.wrapReturn(returnsNullable);
-    expectTypeOf(querySelector).toEqualTypeOf<() => Maybe<string>>();
-  });
-
   test('`isJust` with a Just', () => {
     const testJust: Maybe<string> = MaybeNS.just('test');
 
diff --git a/test/task.test.ts b/test/task.test.ts
index 4aa0c96..b46d6b0 100644
--- a/test/task.test.ts
+++ b/test/task.test.ts
@@ -16,8 +16,8 @@ import Task, {
   AggregateRejection,
   Timer,
   safelyTry,
-  safelyTryOr,
-  safelyTryOrElse,
+  tryOr,
+  tryOrElse,
   safe,
   safeNullable,
   fromPromise,
@@ -83,7 +83,7 @@ describe('`Task`', () => {
   });
 
   test('implements the `PromiseLike` API', async () => {
-    let result = await Task.try(Promise.resolve('hello'));
+    let result = await Task.resolve<string, unknown>('hello');
     expectTypeOf(result).toEqualTypeOf<Result<string, unknown>>();
     expect(unwrap(result)).toBe('hello');
   });
@@ -111,167 +111,6 @@ describe('`Task`', () => {
       });
     });
 
-    describe('`try`', () => {
-      test('when the promise resolves', async () => {
-        let { promise, resolve } = deferred<number, never>();
-        let theTask = Task.try(promise);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, unknown>>();
-
-        resolve(123);
-        let theResult = await theTask;
-        expectTypeOf(theResult).toEqualTypeOf<Result<number, unknown>>();
-        expect(unwrap(theResult)).toBe(123);
-      });
-
-      test('when the promise rejects', async () => {
-        let { promise, reject } = deferred<never, string>();
-        let theTask = Task.try(promise);
-        expectTypeOf(theTask).toEqualTypeOf<Task<never, unknown>>();
-
-        let theError = 'la';
-        reject(theError);
-        let theResult = await theTask;
-        expectTypeOf(theResult).toEqualTypeOf<Result<never, unknown>>();
-        expect(unwrapErr(theResult)).toEqual(theError);
-      });
-    });
-
-    describe('`fromUnsafePromise`', () => {
-      test('when the task resolves', async () => {
-        let { promise, resolve } = deferred<Result<number, string>, never>();
-        let theTask = Task.fromUnsafePromise(promise);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        let theInputResult = Result.ok<number, string>(123);
-        resolve(theInputResult);
-        let theResultingResult = await theTask;
-        expect(theResultingResult).toEqual(Result.ok(123));
-        expectTypeOf(theResultingResult).toEqualTypeOf(theInputResult);
-      });
-
-      test('with a `Promise<Result<T, E>>`', async () => {
-        let { promise, resolve } = deferred<Result<number, string>, never>();
-        let theTask = Task.fromUnsafePromise(promise);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        resolve(Result.ok(123));
-        let result = await theTask;
-        expect(unwrap(result)).toEqual(123);
-      });
-
-      // This jumps through some hoops to test the underlying behavior here: the
-      // way this works under the hood is that the `Task` attaches resolution
-      // and rejection callbacks to the passed promise, and in the case of the
-      // passed promise *rejecting*, it throws a specific kind of error, but it
-      // does so in a promise which is nowhere else exposed, so it is actually
-      // *impossible to catch* other than with this kind of top-level unhandled
-      // error catching mechanism.
-      test('when the task rejects', async () => {
-        // Wire up a promise to wait on this so we can make the test wait till
-        // this is done before exiting. Otherwise, the promise may leak across
-        // tests.
-        let processPromise = new Promise((resolve) => {
-          process.on('unhandledRejection', (error) => {
-            resolve(error);
-          });
-        });
-
-        let { promise, reject } = deferred<Result<number, string>, unknown>();
-        let theTask = Task.fromUnsafePromise(promise);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        let theReason = 'not good';
-        try {
-          // Yes, we must explicitly await both the task and the original
-          // promise, or else the error will not show up deterministically.
-          reject(theReason);
-          await promise;
-          await theTask;
-        } catch (e) {
-          expect(e).toEqual(theReason);
-        }
-
-        let output = await processPromise;
-        expect(output).toBeInstanceOf(UnsafePromise);
-        expect.assertions(2);
-      });
-    });
-
-    describe('`tryOr`', () => {
-      test('when the task resolves', async () => {
-        let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.tryOr(promise, 'lolnope');
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        resolve(123);
-        let result = await theTask;
-        expectTypeOf(result).toEqualTypeOf<Result<number, string>>();
-        expect(unwrap(result)).toBe(123);
-      });
-
-      test('when the task rejects', async () => {
-        let { promise, reject } = deferred<number, string>();
-        let theTask = Task.tryOr(promise, 'lolnope');
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        reject('<this value does not matter>');
-        let result = await theTask;
-        expectTypeOf(result).toEqualTypeOf<Result<number, string>>();
-        expect(unwrapErr(result)).toBe('lolnope');
-      });
-    });
-
-    describe('`tryOrElse', () => {
-      test('with a pending promise', async () => {
-        let { promise, resolve } = deferred<number, never>();
-        let theTask = Task.tryOrElse(promise, stringify);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-        expect(theTask.state).toBe(State.Pending);
-
-        resolve(123);
-        await promise;
-      });
-
-      test('with a resolved promise', async () => {
-        let thePromise = Promise.resolve(123);
-        let theTask = Task.tryOrElse(thePromise, stringify);
-        await theTask;
-        expect(theTask.state).toBe(State.Resolved);
-      });
-
-      test('when the task resolves', async () => {
-        let { promise, resolve } = deferred<number, never>();
-        let theTask = Task.tryOrElse(promise, stringify);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        resolve(123);
-        let result = await theTask;
-        expectTypeOf(result).toEqualTypeOf<Result<number, string>>();
-        expect(unwrap(result)).toBe(123);
-      });
-
-      test('with a rejected promise', async () => {
-        let theError = 'oh teh noes';
-        let thePromise = Promise.reject(theError);
-        let theTask = Task.tryOrElse(thePromise, stringify);
-        let theResult = await theTask;
-        expectTypeOf(theResult).toEqualTypeOf<Result<never, string>>();
-        expect(unwrapErr(theResult)).toEqual(stringify(theError));
-      });
-
-      test('when the task rejects', async () => {
-        let { promise, reject } = deferred<number, string>();
-        let theTask = Task.tryOrElse(promise, stringify);
-        expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
-
-        let theError = 'oh teh noes';
-        reject(theError);
-        let result = await theTask;
-        expectTypeOf(result).toEqualTypeOf<Result<number, string>>();
-        expect(unwrapErr(result)).toBe(stringify(theError));
-      });
-    });
-
     describe('`resolve`', () => {
       test('produces `Task<Unit, never>` when passed no arguments', () => {
         let theTask = Task.resolve();
@@ -324,7 +163,7 @@ describe('`Task`', () => {
     // without going through the `#promise`, which would be unsafe.
     test('`fromResult`', async () => {
       let theResult = Result.ok<number, string>(123);
-      let theTask = Task.fromResult(theResult);
+      let theTask = fromResult(theResult);
       expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
       let result = await theTask;
       expect(result.isOk).toBe(true);
@@ -336,7 +175,7 @@ describe('`Task`', () => {
     describe('`map`', () => {
       test('for a pending promise', async () => {
         let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.tryOrElse(promise, stringify).map((n) => n % 2 == 0);
+        let theTask = tryOrElse(stringify, () => promise).map((n) => n % 2 == 0);
         expectTypeOf(theTask).toEqualTypeOf<Task<boolean, string>>();
 
         resolve(123);
@@ -345,7 +184,7 @@ describe('`Task`', () => {
 
       test('when the promise resolves', async () => {
         let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.tryOrElse(promise, stringify).map((n) => n % 2 == 0);
+        let theTask = tryOrElse(stringify, () => promise).map((n) => n % 2 == 0);
         expectTypeOf(theTask).toEqualTypeOf<Task<boolean, string>>();
 
         resolve(123);
@@ -355,7 +194,7 @@ describe('`Task`', () => {
 
       test('when the promise rejects', async () => {
         let { promise, reject } = deferred<number, string>();
-        let theTask = Task.tryOrElse(promise, stringify).map((n) => n % 2 == 0);
+        let theTask = tryOrElse(stringify, () => promise).map((n) => n % 2 == 0);
         expectTypeOf(theTask).toEqualTypeOf<Task<boolean, string>>();
 
         let theReason = 'nope';
@@ -368,13 +207,13 @@ describe('`Task`', () => {
     describe('`mapRejected`', () => {
       test('for a pending promise', async () => {
         let { promise } = deferred<number, string>();
-        let theTask = Task.try(promise).mapRejected(stringify);
+        let theTask = fromPromise(promise).mapRejected(stringify);
         expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
       });
 
       test('when the promise resolves', async () => {
         let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.try(promise).mapRejected(stringify);
+        let theTask = fromPromise(promise).mapRejected(stringify);
         expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
 
         resolve(123);
@@ -384,7 +223,7 @@ describe('`Task`', () => {
 
       test('when the promise rejects', async () => {
         let { promise, reject } = deferred<number, string>();
-        let theTask = Task.try(promise).mapRejected(stringify);
+        let theTask = fromPromise(promise).mapRejected(stringify);
         expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
 
         let theReason = 'nope';
@@ -466,7 +305,7 @@ describe('`Task`', () => {
     describe('`andThen`', () => {
       test('for a pending promise', async () => {
         let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.tryOrElse(promise, stringify).andThen((n) => Task.resolve(n % 2 == 0));
+        let theTask = tryOrElse(stringify, () => promise).andThen((n) => Task.resolve(n % 2 == 0));
         expectTypeOf(theTask).toEqualTypeOf<Task<boolean, string>>();
 
         resolve(123);
@@ -489,7 +328,9 @@ describe('`Task`', () => {
 
         test('when the second `Task` resolves', async () => {
           let { promise, resolve } = deferred<number, string>();
-          let theTask = Task.tryOrElse(promise, stringify).andThen((n) => Task.resolve(n % 2 == 0));
+          let theTask = tryOrElse(stringify, () => promise).andThen((n) =>
+            Task.resolve(n % 2 == 0)
+          );
           expectTypeOf(theTask).toEqualTypeOf<Task<boolean, string>>();
 
           resolve(123);
@@ -499,7 +340,7 @@ describe('`Task`', () => {
 
         test('when the second `Task` rejects', async () => {
           let { promise, resolve } = deferred<number, string>();
-          let theTask = Task.tryOrElse(promise, stringify).andThen(() => Task.reject('oh no'));
+          let theTask = tryOrElse(stringify, () => promise).andThen(() => Task.reject('oh no'));
           expectTypeOf(theTask).toEqualTypeOf<Task<never, string>>();
 
           resolve(123);
@@ -525,7 +366,7 @@ describe('`Task`', () => {
 
         test('when the second `Task` resolves', async () => {
           let { promise, reject } = deferred<number, string>();
-          let theTask = Task.try(promise).andThen((n) => Task.resolve(n % 2 == 0));
+          let theTask = fromPromise(promise).andThen((n) => Task.resolve(n % 2 == 0));
           expectTypeOf(theTask).toEqualTypeOf<Task<boolean, unknown>>();
 
           let theReason = 'nope';
@@ -723,7 +564,7 @@ describe('`Task`', () => {
 
     describe('`match`', () => {
       test('with a resolved task', async () => {
-        await Task.tryOrElse(Promise.resolve(123), stringify).match({
+        await tryOrElse(stringify, () => Promise.resolve(123)).match({
           Resolved: (value) => expect(value).toBe(123),
           Rejected: (_reason) => expect.unreachable(),
         });
@@ -731,7 +572,7 @@ describe('`Task`', () => {
       });
 
       test('with a rejected task', async () => {
-        await Task.tryOrElse(Promise.reject(123), stringify).match({
+        await tryOrElse(stringify, () => Promise.reject(123)).match({
           Resolved: (_value) => expect.unreachable(),
           Rejected: (reason) => expect(reason).toEqual(stringify(123)),
         });
@@ -788,7 +629,7 @@ describe('`Task`', () => {
 
       test('with a passed-in-promise', async () => {
         let { promise: theInputPromise, resolve } = deferred();
-        let theTask = Task.try(theInputPromise);
+        let theTask = fromPromise(theInputPromise);
 
         let theValue = 123;
         resolve(theValue);
@@ -871,32 +712,26 @@ describe('`Task`', () => {
   describe('accessors', () => {
     describe('state', () => {
       test('is initially Pending', async () => {
-        let { promise, resolve } = deferred<number, string>();
-        let theTask = Task.try(promise);
-        expect(theTask.state).toBe(State.Pending);
-        // don't leak it!
-        resolve(123);
-        await promise;
+        let { task } = Task.withResolvers<number, string>();
+        expect(task.state).toBe(State.Pending);
       });
 
       test('is Resolved once the promise resolves', async () => {
-        let { promise, resolve } = deferred<number, string>();
-        let successfulTask = Task.try(promise);
+        let { task, resolve } = Task.withResolvers<number, string>();
         resolve(123);
-        let result = await successfulTask;
-        expect(successfulTask.state).toBe(State.Resolved);
+        let result = await task;
+        expect(task.state).toBe(State.Resolved);
         expect(unwrap(result)).toBe(123);
       });
 
       test('is Rejected if the promise rejects', async () => {
-        let { promise, reject } = deferred<number, string>();
+        let { task, reject } = Task.withResolvers<number, string>();
 
-        let theTask = Task.try(promise);
         let anError = 'oh teh noes';
         reject(anError);
 
-        let result = await theTask;
-        expect(theTask.state).toBe(State.Rejected);
+        let result = await task;
+        expect(task.state).toBe(State.Rejected);
         expect(unwrapErr(result)).toEqual(anError);
       });
     });
@@ -966,37 +801,38 @@ describe('`Task`', () => {
 
   describe('narrowing', () => {
     test('pending', async () => {
-      let { promise, resolve } = deferred<number, string>();
-      let theTask = Task.try(promise);
+      let { task, resolve } = Task.withResolvers<number, string>();
 
-      if (theTask.state === State.Pending) {
-        expect(theTask.isPending).toBe(true);
-        expect(theTask.isResolved).toBe(false);
-        expect(theTask.isRejected).toBe(false);
+      if (task.state === State.Pending) {
+        expect(task.isPending).toBe(true);
+        expect(task.isResolved).toBe(false);
+        expect(task.isRejected).toBe(false);
       }
 
       resolve(123);
-      await theTask;
+      await task;
     });
 
     test('resolved', async () => {
-      let { promise, resolve } = deferred<number, string>();
-      let theTask = Task.try(promise);
+      let { task, resolve } = Task.withResolvers<number, string>();
 
       resolve(123);
-      await theTask;
+      await task;
 
-      if (theTask.state === State.Resolved) {
-        expect(theTask.value).toBe(123);
-        expect(theTask.isPending).toBe(false);
-        expect(theTask.isResolved).toBe(true);
-        expect(theTask.isRejected).toBe(false);
+      if (task.state === State.Resolved) {
+        expect(task.value).toBe(123);
+        expect(task.isPending).toBe(false);
+        expect(task.isResolved).toBe(true);
+        expect(task.isRejected).toBe(false);
       }
     });
 
     test('rejected', async () => {
       let { promise, reject } = deferred<number, string>();
-      let theTask = Task.tryOrElse(promise, (e) => `${e}`);
+      let theTask = tryOrElse(
+        (e) => `${e}`,
+        () => promise
+      );
 
       let theError = 'oh teh noes';
       reject(theError);
@@ -1885,14 +1721,14 @@ describe('module-scope functions', () => {
   describe('safelyTryOr', () => {
     describe('with a non-throwing function', () => {
       test('with a promise that resolves', async () => {
-        let theTask = safelyTryOr('error', () => Promise.resolve(123));
+        let theTask = tryOr('error', () => Promise.resolve(123));
         expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
         let theResult = await theTask;
         expect(unwrap(theResult)).toBe(123);
       });
 
       test('with a promise that rejects', async () => {
-        let theTask = safelyTryOr('error', () => Promise.reject(123));
+        let theTask = tryOr('error', () => Promise.reject(123));
         expectTypeOf(theTask).toEqualTypeOf<Task<never, string>>();
         let theResult = await theTask;
         expect(unwrapErr(theResult)).toBe('error');
@@ -1901,7 +1737,7 @@ describe('module-scope functions', () => {
 
     describe('with a throwing function', () => {
       test('with a promise that resolves', async () => {
-        let theTask = safelyTryOr('error', (): Promise<number> => {
+        let theTask = tryOr('error', (): Promise<number> => {
           throw new Error('NOPE');
           return Promise.resolve(123);
         });
@@ -1911,7 +1747,7 @@ describe('module-scope functions', () => {
       });
 
       test('with a promise that rejects', async () => {
-        let theTask = safelyTryOr('error', (): Promise<number> => {
+        let theTask = tryOr('error', (): Promise<number> => {
           throw new Error('NOPE');
           return Promise.reject(123);
         });
@@ -1925,14 +1761,14 @@ describe('module-scope functions', () => {
   describe('safelyTryOrElse', () => {
     describe('with a non-throwing function', () => {
       test('with a promise that resolves', async () => {
-        let theTask = safelyTryOrElse(stringify, () => Promise.resolve(123));
+        let theTask = tryOrElse(stringify, () => Promise.resolve(123));
         expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
         let theResult = await theTask;
         expect(unwrap(theResult)).toBe(123);
       });
 
       test('with a promise that rejects', async () => {
-        let theTask = safelyTryOrElse(stringify, () => Promise.reject(123));
+        let theTask = tryOrElse(stringify, () => Promise.reject(123));
         expectTypeOf(theTask).toEqualTypeOf<Task<never, string>>();
         let theResult = await theTask;
         expect(unwrapErr(theResult)).toBe(stringify(123));
@@ -1941,7 +1777,7 @@ describe('module-scope functions', () => {
 
     describe('with a throwing function', () => {
       test('with a promise that resolves', async () => {
-        let theTask = safelyTryOrElse(stringify, (): Promise<number> => {
+        let theTask = tryOrElse(stringify, (): Promise<number> => {
           throw new Error('NOPE');
           return Promise.resolve(123);
         });
@@ -1952,7 +1788,7 @@ describe('module-scope functions', () => {
       });
 
       test('with a promise that rejects', async () => {
-        let theTask = safelyTryOrElse(stringify, (): Promise<number> => {
+        let theTask = tryOrElse(stringify, (): Promise<number> => {
           throw new Error('NOPE');
           return Promise.reject(123);
         });
@@ -2008,7 +1844,6 @@ describe('module-scope functions', () => {
           let theTask = safeExample(123);
           expectTypeOf(theTask).toEqualTypeOf<Task<number, unknown>>();
           await theTask;
-          console.log(theTask.toString());
           if (theTask.isResolved) {
             expect(theTask.value).toBe(123);
           } else {
@@ -2020,7 +1855,6 @@ describe('module-scope functions', () => {
           let theTask = safeExample(123, { rejectPromise: true });
           expectTypeOf(theTask).toEqualTypeOf<Task<number, unknown>>();
           await theTask;
-          console.log(theTask.toString());
           if (theTask.isRejected) {
             expect(theTask.reason).toBe(REJECTION_REASON);
           } else {
@@ -2053,7 +1887,6 @@ describe('module-scope functions', () => {
           let theTask = safeExample(123);
           expectTypeOf(theTask).toEqualTypeOf<Task<number, string>>();
           await theTask;
-          console.log(theTask.toString());
           if (theTask.isResolved) {
             expect(theTask.value).toBe(123);
           } else {