From bb6c889127063e8e9eaa6d5808b4bd2fa38cbe92 Mon Sep 17 00:00:00 2001 From: Aura Date: Sat, 2 Nov 2024 14:38:57 +0100 Subject: [PATCH] feat(Option): add `isNoneOr` (#824) --- packages/result/src/lib/Option.ts | 27 +++++++++++++++++++++++++ packages/result/tests/Option.test.ts | 30 ++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+) diff --git a/packages/result/src/lib/Option.ts b/packages/result/src/lib/Option.ts index 11528c497b..d92e3fbed5 100644 --- a/packages/result/src/lib/Option.ts +++ b/packages/result/src/lib/Option.ts @@ -88,6 +88,33 @@ export class Option { return !this[ExistsProperty]; } + /** + * Returns `true` if the option is a `None` value or the value inside of it matches a predicate. + * + * @example + * ```typescript + * const x: Option = some(2); + * assert.equal(x.isNoneOr((x) => x > 1), true); + * ``` + * @example + * ```typescript + * const x: Option = some(0); + * assert.equal(x.isNoneOr((x) => x > 1), false); + * ``` + * @example + * ```typescript + * const x: Option = none; + * assert.equal(x.isNoneOr((x) => x > 1), true); + * ``` + * + * @see {@link https://doc.rust-lang.org/std/option/enum.Option.html#method.is_none_or} + */ + public isNoneOr(cb: (value: T) => value is R): this is None | Some; + public isNoneOr(cb: (value: T) => R): If; + public isNoneOr(cb: (value: T) => R): If { + return this.match({ some: (value) => cb(value), none: () => true }); + } + /** * Returns the contained `Some` value. * @param message The message for the error. diff --git a/packages/result/tests/Option.test.ts b/packages/result/tests/Option.test.ts index 8c8a2388d1..b1ac40f0ae 100644 --- a/packages/result/tests/Option.test.ts +++ b/packages/result/tests/Option.test.ts @@ -58,6 +58,36 @@ describe('Option', () => { }); }); + describe('isNoneOr', () => { + test('GIVEN some AND true-returning callback THEN returns true', () => { + const x = some(2); + const cb = vi.fn((value: number) => value > 1); + + expect(x.isNoneOr(cb)).toBe(true); + expect(cb).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledWith(2); + expect(cb).toHaveLastReturnedWith(true); + }); + + test('GIVEN some AND false-returning callback THEN returns false', () => { + const x = some(0); + const cb = vi.fn((value: number) => value > 1); + + expect(x.isNoneOr(cb)).toBe(false); + expect(cb).toHaveBeenCalledTimes(1); + expect(cb).toHaveBeenCalledWith(0); + expect(cb).toHaveLastReturnedWith(false); + }); + + test('GIVEN none THEN always returns false', () => { + const x = none; + const cb = vi.fn((value: number) => value > 1); + + expect(x.isNoneOr(cb)).toBe(true); + expect(cb).not.toHaveBeenCalled(); + }); + }); + describe('expect', () => { test('GIVEN ok THEN returns value', () => { const x = some(2);