From e60c26b0891c063bb5e0af19ba6c2f3097066374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Levilain?= Date: Fri, 18 Jul 2025 11:32:04 +0200 Subject: [PATCH 1/2] Add getOrThrow() helper to Option and Result --- docs/docs/option.md | 16 ++++++++++++++++ docs/docs/result.md | 16 ++++++++++++++++ src/OptionResult.ts | 22 ++++++++++++++++++++++ test/Option.test.ts | 7 +++++++ test/Result.test.ts | 7 +++++++ 5 files changed, 68 insertions(+) diff --git a/docs/docs/option.md b/docs/docs/option.md index e256b21..95b372b 100644 --- a/docs/docs/option.md +++ b/docs/docs/option.md @@ -173,6 +173,22 @@ if (option.isSome()) { } ``` +### .getOrThrow() + +```ts +Option.getOrThrow(): A | never +``` + +Returns the value contained in `Some(value)`, otherwise will throw an error. + +```ts title="Examples" +const value = Option.Some(1).getOrThrow(); +// 2 + +const value = Option.None().getOrThrow(); +// Uncaught: Tried to unwrap a Option.None value +``` + ### .isSome() ```ts diff --git a/docs/docs/result.md b/docs/docs/result.md index d4155f7..a850f67 100644 --- a/docs/docs/result.md +++ b/docs/docs/result.md @@ -168,6 +168,22 @@ Result.Error(2).getOr(1); // 1 ``` +### .getOrThrow() + +```ts +Result.getOrThrow(): A | never +``` + +If the result is `Ok(value)` returns `value`, otherwise will throw an error. + +```ts title="Examples" +const value = Result.Ok(1).getOrThrow(); +// 2 + +const value = Result.Error(2).getOrThrow(); +// Uncaught: Tried to unwrap a Result.Error value +``` + ### .mapOr(defaultValue, mapper) ```ts diff --git a/src/OptionResult.ts b/src/OptionResult.ts index 40101ae..a4c94c3 100644 --- a/src/OptionResult.ts +++ b/src/OptionResult.ts @@ -210,6 +210,17 @@ class __Option { return (this as Some).value; } + /** + * Return the value if present, otherwise throw an error + */ + getOrThrow(this: Option): A | never { + if (this === NONE) { + throw new Error("Tried to unwrap a Option.None value"); + } + + return (this as Some).value; + } + /** * Return the value if present, and the fallback otherwise * @@ -589,6 +600,17 @@ class __Result { return this.tag === "Ok" ? this.value : defaultValue; } + /** + * Return the value if present, otherwise throw an error + */ + getOrThrow(this: Result): A | never { + if (this.tag === "Error") { + throw new Error("Tried to unwrap a Result.Error value"); + } + + return this.value; + } + /** * Maps the value if present, returns the fallback otherwise * diff --git a/test/Option.test.ts b/test/Option.test.ts index d069d69..9981a15 100644 --- a/test/Option.test.ts +++ b/test/Option.test.ts @@ -42,6 +42,13 @@ test("Option.getOr", () => { expect(Option.None().getOr(0)).toEqual(0); }); +test("Option.getOrThrow", () => { + expect(Option.Some(1).getOrThrow()).toEqual(1); + expect(() => Option.None().getOrThrow()).toThrowError( + "Tried to unwrap a Option.None value", + ); +}); + test("Option.mapOr", () => { expect(Option.Some(1).mapOr(0, (x) => x * 2)).toEqual(2); expect(Option.None().mapOr(0, (x) => x * 2)).toEqual(0); diff --git a/test/Result.test.ts b/test/Result.test.ts index 00936a1..ca36b5e 100644 --- a/test/Result.test.ts +++ b/test/Result.test.ts @@ -71,6 +71,13 @@ test("Result.getOr", () => { expect(Result.Error(1).getOr(0)).toEqual(0); }); +test("Result.getOrThrow", () => { + expect(Result.Ok(1).getOrThrow()).toEqual(1); + expect(() => Result.Error(1).getOrThrow()).toThrowError( + "Tried to unwrap a Result.Error value", + ); +}); + test("Result.mapOr", () => { expect(Result.Ok(1).mapOr(0, (x) => x * 2)).toEqual(2); expect(Result.Error(1).mapOr(0, (x) => x * 2)).toEqual(0); From 8804726da62dc62390315eb8215229c79a7c5ebe Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?J=C3=A9r=C3=A9my=20Levilain?= Date: Fri, 25 Jul 2025 11:31:27 +0200 Subject: [PATCH 2/2] Add getOrThrow() helper to AsyncData --- src/AsyncData.ts | 10 ++++++++++ src/OptionResult.ts | 4 ++++ test/AsyncData.test.ts | 10 ++++++++++ test/Result.test.ts | 3 +++ 4 files changed, 27 insertions(+) diff --git a/src/AsyncData.ts b/src/AsyncData.ts index 13de03b..f73d4e3 100644 --- a/src/AsyncData.ts +++ b/src/AsyncData.ts @@ -257,6 +257,16 @@ class __AsyncData { return (this as Done).value; } + /** + * Return the loaded value if present, otherwise throw an error + */ + getOrThrow(this: AsyncData): A | never { + if (this === NOT_ASKED || this === LOADING) { + throw new Error("Tried to unwrap an incomplete AsyncData"); + } + return (this as Done).value; + } + /** * Maps the value if present, returns the fallback otherwise * diff --git a/src/OptionResult.ts b/src/OptionResult.ts index a4c94c3..c756e37 100644 --- a/src/OptionResult.ts +++ b/src/OptionResult.ts @@ -605,6 +605,10 @@ class __Result { */ getOrThrow(this: Result): A | never { if (this.tag === "Error") { + if (typeof this.error === "string") { + throw new Error(this.error); + } + throw new Error("Tried to unwrap a Result.Error value"); } diff --git a/test/AsyncData.test.ts b/test/AsyncData.test.ts index b625fc6..31b0719 100644 --- a/test/AsyncData.test.ts +++ b/test/AsyncData.test.ts @@ -57,6 +57,16 @@ test("AsyncData.getOr", () => { expect(AsyncData.Done(5).getOr(0)).toEqual(5); }); +test("AsyncData.getOrThrow", () => { + expect(AsyncData.Done(5).getOrThrow()).toEqual(5); + expect(() => AsyncData.Loading().getOrThrow()).toThrowError( + "Tried to unwrap an incomplete AsyncData", + ); + expect(() => AsyncData.NotAsked().getOrThrow()).toThrowError( + "Tried to unwrap an incomplete AsyncData", + ); +}); + test("AsyncData.mapOk", () => { expect(AsyncData.NotAsked().mapOr(0, (x) => x * 2)).toEqual(0); expect(AsyncData.Loading().mapOr(0, (x) => x * 2)).toEqual(0); diff --git a/test/Result.test.ts b/test/Result.test.ts index ca36b5e..216eb11 100644 --- a/test/Result.test.ts +++ b/test/Result.test.ts @@ -76,6 +76,9 @@ test("Result.getOrThrow", () => { expect(() => Result.Error(1).getOrThrow()).toThrowError( "Tried to unwrap a Result.Error value", ); + expect(() => Result.Error("AnErrorMessage").getOrThrow()).toThrowError( + "AnErrorMessage", + ); }); test("Result.mapOr", () => {