@antithrow/std
Non-throwing wrappers around standard JavaScript globals. Each function mirrors its built-in counterpart but returns a Result or ResultAsync instead of throwing.
Installation
- npm
- Yarn
- pnpm
- Bun
npm install @antithrow/std
yarn add @antithrow/std
pnpm add @antithrow/std
bun add @antithrow/std
JSON
JSON.parse()
JSON.parse<T = unknown>(
text: string,
reviver?: (key: string, value: unknown) => unknown,
): Result<T, SyntaxError>
Parses a JSON string. Returns Err<SyntaxError> for malformed input.
import { JSON } from "@antithrow/std";
JSON.parse<{ name: string }>('{"name": "Alice"}');
// ok({ name: "Alice" })
JSON.parse("invalid json");
// err(SyntaxError)
JSON.stringify()
JSON.stringify(
value: unknown,
replacer?: JsonStringifyReplacer,
space?: string | number,
): Result<string | undefined, TypeError>
Converts a value to a JSON string. Returns Err<TypeError> for circular references. Returns Ok<undefined> for non-serializable top-level values (e.g., undefined, symbol, functions).
import { JSON } from "@antithrow/std";
JSON.stringify({ a: 1 });
// ok('{"a":1}')
const circular: Record<string, unknown> = {};
circular.self = circular;
JSON.stringify(circular);
// err(TypeError)
fetch
fetch()
fetch(
input: string | URL | Request,
init?: RequestInit,
): ResultAsync<Response, DOMException | TypeError>
Wraps globalThis.fetch. Non-2xx responses are Ok — only network errors and aborts become Err.
import { fetch } from "@antithrow/std";
const result = await fetch("https://api.example.com/users");
// Ok<Response> (even for 404, 500, etc.)
// Err<DOMException | TypeError> (network failure, abort, etc.)
Non-2xx status codes are not errors. If you want to treat them as errors, use andThen:
fetch("https://api.example.com/users").andThen((response) => {
if (!response.ok) {
return err({ status: response.status, statusText: response.statusText });
}
return ok(response);
});
Response
Functional wrappers around Response body-reading methods. Each accepts a Response object and returns a ResultAsync.
Response.json()
Response.json<T = unknown>(
response: Response,
): ResultAsync<T, DOMException | TypeError | SyntaxError>
Parses the response body as JSON.
import { fetch, Response } from "@antithrow/std";
const result = await fetch("https://api.example.com/users").andThen((r) =>
Response.json<User[]>(r),
);
Response.text()
Response.text(
response: Response,
): ResultAsync<string, DOMException | TypeError>
Reads the response body as text.
import { Response } from "@antithrow/std";
const result = await Response.text(response);
Response.arrayBuffer()
Response.arrayBuffer(
response: Response,
): ResultAsync<ArrayBuffer, DOMException | TypeError | RangeError>
Reads the response body as an ArrayBuffer.
Response.blob()
Response.blob(
response: Response,
): ResultAsync<Blob, DOMException | TypeError>
Reads the response body as a Blob.
Response.formData()
Response.formData(
response: Response,
): ResultAsync<FormData, DOMException | TypeError>
Reads the response body as FormData.
Base64
atob()
atob(data: string): Result<string, DOMException>
Decodes a base64-encoded string.
import { atob } from "@antithrow/std";
atob("SGVsbG8="); // ok("Hello")
atob("!!!!"); // err(DOMException)
btoa()
btoa(data: string): Result<string, DOMException>
Encodes a string to base64.
import { btoa } from "@antithrow/std";
btoa("Hello"); // ok("SGVsbG8=")
btoa("🙂"); // err(DOMException) — non-Latin1 characters
URI
decodeURI()
decodeURI(encodedURI: string): Result<string, URIError>
Decodes a percent-encoded URI.
import { decodeURI } from "@antithrow/std";
decodeURI("https://example.com/hello%20world");
// ok("https://example.com/hello world")
decodeURIComponent()
decodeURIComponent(encodedURIComponent: string): Result<string, URIError>
Decodes a percent-encoded URI component.
import { decodeURIComponent } from "@antithrow/std";
decodeURIComponent("hello%20world"); // ok("hello world")
decodeURIComponent("%E0%A4%A"); // err(URIError) — malformed
encodeURI()
encodeURI(uri: string): Result<string, URIError>
Encodes a URI, preserving special URI characters.
import { encodeURI } from "@antithrow/std";
encodeURI("https://example.com/hello world");
// ok("https://example.com/hello%20world")
encodeURIComponent()
encodeURIComponent(
uriComponent: string | number | boolean,
): Result<string, URIError>
Encodes a URI component.
import { encodeURIComponent } from "@antithrow/std";
encodeURIComponent("hello world"); // ok("hello%20world")
Structured Clone
structuredClone()
structuredClone<T>(
value: T,
options?: StructuredSerializeOptions,
): Result<T, DOMException>
Deep clones a value using the structured clone algorithm.
import { structuredClone } from "@antithrow/std";
structuredClone({ a: 1, b: [2, 3] }); // ok({ a: 1, b: [2, 3] })
structuredClone(() => {}); // err(DOMException) — functions not cloneable