{"id":19251985,"url":"https://github.com/jiangjie/happy-rusty","last_synced_at":"2026-01-16T21:27:51.619Z","repository":{"id":235802250,"uuid":"791285691","full_name":"JiangJie/happy-rusty","owner":"JiangJie","description":"Rust's Option, Result, and sync primitives for JavaScript/TypeScript - Better error handling and null-safety patterns.","archived":false,"fork":false,"pushed_at":"2026-01-16T03:50:55.000Z","size":952,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2026-01-16T18:15:59.936Z","etag":null,"topics":["async","channel","concurrency","controlflow","err","error-handling","fnonce","lazy","mutex","none","null-safety","ok","once","option","result","rust","rwlock","some","typescript"],"latest_commit_sha":null,"homepage":"","language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/JiangJie.png","metadata":{"files":{"readme":"README.cn.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2024-04-24T12:47:26.000Z","updated_at":"2026-01-16T03:50:59.000Z","dependencies_parsed_at":"2024-05-21T16:44:10.711Z","dependency_job_id":"657529bd-b8e4-48d1-b3dd-bddf72ee2853","html_url":"https://github.com/JiangJie/happy-rusty","commit_stats":null,"previous_names":["jiangjie/happy-rusty"],"tags_count":27,"template":false,"template_full_name":null,"purl":"pkg:github/JiangJie/happy-rusty","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiangJie%2Fhappy-rusty","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiangJie%2Fhappy-rusty/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiangJie%2Fhappy-rusty/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiangJie%2Fhappy-rusty/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/JiangJie","download_url":"https://codeload.github.com/JiangJie/happy-rusty/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/JiangJie%2Fhappy-rusty/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":28483102,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-01-16T11:59:17.896Z","status":"ssl_error","status_checked_at":"2026-01-16T11:55:55.838Z","response_time":107,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["async","channel","concurrency","controlflow","err","error-handling","fnonce","lazy","mutex","none","null-safety","ok","once","option","result","rust","rwlock","some","typescript"],"created_at":"2024-11-09T18:24:53.764Z","updated_at":"2026-01-16T21:27:51.585Z","avatar_url":"https://github.com/JiangJie.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# happy-rusty\n\n[![License](https://img.shields.io/npm/l/happy-rusty.svg)](LICENSE)\n[![Build Status](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml/badge.svg)](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml)\n[![codecov](https://codecov.io/gh/JiangJie/happy-rusty/graph/badge.svg)](https://codecov.io/gh/JiangJie/happy-rusty)\n[![NPM version](https://img.shields.io/npm/v/happy-rusty.svg)](https://npmjs.org/package/happy-rusty)\n[![NPM downloads](https://badgen.net/npm/dm/happy-rusty)](https://npmjs.org/package/happy-rusty)\n[![JSR Version](https://jsr.io/badges/@happy-js/happy-rusty)](https://jsr.io/@happy-js/happy-rusty)\n[![JSR Score](https://jsr.io/badges/@happy-js/happy-rusty/score)](https://jsr.io/@happy-js/happy-rusty/score)\n\n将 Rust 的 `Option`、`Result` 和同步原语带入 JavaScript/TypeScript - 更好的错误处理和空值安全模式。\n\n---\n\n[English](README.md) | [API 文档](https://jiangjie.github.io/happy-rusty/)\n\n---\n\n## 特性\n\n- **Option\u0026lt;T\u0026gt;** - 表示可选值：每个 `Option` 要么是 `Some(T)`，要么是 `None`\n- **Result\u0026lt;T, E\u0026gt;** - 表示成功（`Ok(T)`）或失败（`Err(E)`）\n- **同步原语** - Rust 风格的 `Once\u003cT\u003e`、`OnceAsync\u003cT\u003e`、`Lazy\u003cT\u003e`、`LazyAsync\u003cT\u003e`、`Mutex\u003cT\u003e`、`RwLock\u003cT\u003e` 和 `Channel\u003cT\u003e`\n- **控制流** - 用于短路操作的 `ControlFlow\u003cB, C\u003e`，包含 `Break` 和 `Continue`\n- **FnOnce** - 一次性可调用函数封装（`FnOnce` 和 `FnOnceAsync`）\n- **完整的 TypeScript 支持**，具有严格的类型推断\n- **异步支持** - 所有转换方法都有异步版本\n- **零依赖**\n- **运行时不可变** - 所有实例都通过 `Object.freeze()` 冻结\n- **跨运行时** - 支持 Node.js、Deno、Bun 和浏览器\n\n## 安装\n\n```sh\n# npm\nnpm install happy-rusty\n\n# yarn\nyarn add happy-rusty\n\n# pnpm\npnpm add happy-rusty\n\n# JSR (Deno)\ndeno add @happy-js/happy-rusty\n\n# JSR (Bun)\nbunx jsr add @happy-js/happy-rusty\n```\n\n## 快速开始\n\n```ts\nimport { Some, None, Ok, Err } from 'happy-rusty';\n\n// Option - 处理可空值\nfunction findUser(id: number): Option\u003cUser\u003e {\n    const user = database.get(id);\n    return user ? Some(user) : None;\n}\n\nconst user = findUser(1)\n    .map(u =\u003e u.name)\n    .unwrapOr('Guest');\n\n// Result - 处理错误\nfunction parseJSON\u003cT\u003e(json: string): Result\u003cT, Error\u003e {\n    try {\n        return Ok(JSON.parse(json));\n    } catch (e) {\n        return Err(e as Error);\n    }\n}\n\nconst config = parseJSON\u003cConfig\u003e(jsonStr)\n    .map(c =\u003e c.settings)\n    .unwrapOrElse(err =\u003e {\n        console.error('解析失败:', err);\n        return defaultSettings;\n    });\n```\n\n## API 概览\n\n### Option\u0026lt;T\u0026gt;\n\n| 分类 | 方法 |\n|------|------|\n| **构造器** | `Some(value)`, `None` |\n| **查询** | `isSome()`, `isNone()`, `isSomeAnd(fn)` |\n| **提取** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |\n| **转换** | `map(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `filter(fn)`, `flatten()` |\n| **布尔操作** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)`, `xor(other)` |\n| **类型转换** | `okOr(err)`, `okOrElse(fn)`, `transpose()` |\n| **组合** | `zip(other)`, `zipWith(other, fn)`, `unzip()` |\n| **副作用** | `inspect(fn)` |\n| **比较** | `eq(other)` |\n\n### Result\u0026lt;T, E\u0026gt;\n\n| 分类 | 方法 |\n|------|------|\n| **构造器** | `Ok(value)`, `Ok()` (void), `Err(error)` |\n| **查询** | `isOk()`, `isErr()`, `isOkAnd(fn)`, `isErrAnd(fn)` |\n| **提取 Ok** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |\n| **提取 Err** | `expectErr(msg)`, `unwrapErr()` |\n| **转换** | `map(fn)`, `mapErr(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `flatten()` |\n| **布尔操作** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)` |\n| **类型转换** | `ok()`, `err()`, `transpose()` |\n| **类型断言** | `asOk\u003cF\u003e()`, `asErr\u003cU\u003e()` |\n| **副作用** | `inspect(fn)`, `inspectErr(fn)` |\n| **比较** | `eq(other)` |\n\n### 异步方法\n\n所有转换方法都有带 `Async` 后缀的异步变体（如 `andThenAsync`、`mapAsync`、`unwrapOrElseAsync`）。\n\n### 类型别名\n\n```ts\ntype AsyncOption\u003cT\u003e = Promise\u003cOption\u003cT\u003e\u003e;\ntype AsyncResult\u003cT, E\u003e = Promise\u003cResult\u003cT, E\u003e\u003e;\ntype IOResult\u003cT\u003e = Result\u003cT, Error\u003e;          // 用于 I/O 操作\ntype AsyncIOResult\u003cT\u003e = Promise\u003cIOResult\u003cT\u003e\u003e; // 异步 I/O 操作\n```\n\n### 工具函数\n\n```ts\nimport { tryResult, tryAsyncResult } from 'happy-rusty';\n\n// 捕获异常为 Result（类似 Promise.try，但返回 Result）\nconst parsed = tryResult(JSON.parse, jsonString);  // Ok(value) 或 Err(error)\nconst response = await tryAsyncResult(fetch, '/api/data');\n```\n\n### 同步原语\n\n```ts\nimport { Lazy, LazyAsync, Mutex, Channel } from 'happy-rusty';\n\n// Lazy - 首次访问时计算一次\nconst expensive = Lazy(() =\u003e computeExpensiveValue());\nexpensive.force();  // 计算一次后缓存\n\n// LazyAsync - 异步惰性初始化（并发安全）\nconst db = LazyAsync(async () =\u003e Database.connect(url));\nawait db.force();  // 只建立一次连接，并发调用会等待\n\n// Mutex - 异步互斥锁\nconst state = Mutex({ count: 0 });\nawait state.withLock(async (s) =\u003e { s.count += 1; });\n\n// Channel - MPMC 异步消息传递\nconst ch = Channel\u003cstring\u003e(10);  // 有界容量\nawait ch.send('hello');\nfor await (const msg of ch) { console.log(msg); }\n```\n\n## 示例\n\n- [Option](examples/core/option/option.ts) / [AsyncOption](examples/core/option/option.async.ts)\n- [Result](examples/core/result/result.ts) / [AsyncResult](examples/core/result/result.async.ts)\n- [Once](examples/std/sync/once.ts) / [OnceAsync](examples/std/sync/once_async.ts)\n- [Lazy](examples/std/sync/lazy.ts) / [LazyAsync](examples/std/sync/lazy_async.ts)\n- [Mutex](examples/std/sync/mutex.ts)\n- [RwLock](examples/std/sync/rwlock.ts)\n- [Channel](examples/std/sync/channel.ts)\n- [ControlFlow](examples/std/ops/control_flow.ts)\n- [FnOnce](examples/std/ops/fn_once.ts) / [FnOnceAsync](examples/std/ops/fn_once_async.ts)\n\n## 设计说明\n\n### 不可变性\n\n所有类型（`Option`、`Result`、`ControlFlow`、`Lazy`、`LazyAsync`、`Once`、`OnceAsync`、`Mutex`、`MutexGuard`、`RwLock`、`Channel`、`Sender`、`Receiver`、`FnOnce`、`FnOnceAsync`）都通过 `Object.freeze()` 实现**运行时不可变**。这可以防止意外修改方法或属性：\n\n```ts\nconst some = Some(42);\nsome.unwrap = () =\u003e 0;  // TypeError: Cannot assign to read only property\n```\n\n**为什么 TypeScript 接口没有使用 `readonly`？**\n\n我们有意在接口的方法签名中省略了 `readonly` 修饰符。虽然这看起来可能会降低类型安全性，但有以下几个原因：\n\n1. **继承兼容性** - `None` 类型继承自 `Option\u003cnever\u003e`。TypeScript 的箭头函数属性语法（`readonly prop: () =\u003e T`）使用逆变参数检查，这会导致 `None`（参数为 `never`）与 `Option\u003cT\u003e` 不兼容。方法语法（`method(): T`）使用双变参数检查，使继承能够正常工作。\n\n2. **运行时保护已足够** - `Object.freeze()` 已经在运行时阻止了重新赋值。添加 `readonly` 只提供编译时检查，在已有运行时保护的情况下收益有限。\n\n3. **更简洁的 API** - 避免使用 `Mutable*` + `Readonly\u003c\u003e` 模式可以保持导出类型的简洁和文档的可读性。\n\n4. **测试验证不可变性** - 我们的测试套件明确验证了所有实例都被冻结并且会拒绝属性修改。\n\n## 为什么选择 happy-rusty？\n\nJavaScript 的 `null`/`undefined` 和 try-catch 模式会导致：\n- 未捕获的空引用错误\n- 遗忘的错误处理\n- 冗长的 try-catch 代码块\n- 不清晰的函数契约\n\n`happy-rusty` 提供了 Rust 久经考验的模式：\n- **显式可选性** - `Option\u003cT\u003e` 在类型中明确表示值的缺失\n- **显式错误** - `Result\u003cT, E\u003e` 强制考虑错误处理\n- **链式调用** - 无需嵌套 if-else 或 try-catch 即可转换值\n- **类型安全** - 完整的 TypeScript 支持，具有严格的类型推断\n\n## 许可证\n\n[MIT](LICENSE)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjiangjie%2Fhappy-rusty","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjiangjie%2Fhappy-rusty","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjiangjie%2Fhappy-rusty/lists"}