happy-rusty 1.5.0 → 1.6.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (43) hide show
  1. package/CHANGELOG.md +214 -0
  2. package/LICENSE +21 -674
  3. package/README.cn.md +265 -19
  4. package/README.md +261 -21
  5. package/dist/main.cjs +382 -32
  6. package/dist/main.cjs.map +1 -1
  7. package/dist/main.mjs +374 -33
  8. package/dist/main.mjs.map +1 -1
  9. package/dist/types.d.ts +2002 -52
  10. package/package.json +38 -25
  11. package/dist/types.d.ts.map +0 -1
  12. package/docs/README.md +0 -47
  13. package/docs/functions/Err.md +0 -46
  14. package/docs/functions/Ok.md +0 -70
  15. package/docs/functions/Some.md +0 -45
  16. package/docs/functions/isOption.md +0 -35
  17. package/docs/functions/isResult.md +0 -36
  18. package/docs/functions/promiseToAsyncResult.md +0 -50
  19. package/docs/interfaces/None.md +0 -979
  20. package/docs/interfaces/Option.md +0 -857
  21. package/docs/interfaces/Result.md +0 -903
  22. package/docs/type-aliases/AsyncIOResult.md +0 -24
  23. package/docs/type-aliases/AsyncOption.md +0 -24
  24. package/docs/type-aliases/AsyncResult.md +0 -25
  25. package/docs/type-aliases/AsyncVoidIOResult.md +0 -17
  26. package/docs/type-aliases/AsyncVoidResult.md +0 -23
  27. package/docs/type-aliases/IOResult.md +0 -24
  28. package/docs/type-aliases/VoidIOResult.md +0 -17
  29. package/docs/type-aliases/VoidResult.md +0 -23
  30. package/docs/variables/None.md +0 -18
  31. package/docs/variables/RESULT_FALSE.md +0 -18
  32. package/docs/variables/RESULT_TRUE.md +0 -18
  33. package/docs/variables/RESULT_VOID.md +0 -17
  34. package/docs/variables/RESULT_ZERO.md +0 -18
  35. package/src/enum/constants.ts +0 -30
  36. package/src/enum/core.ts +0 -635
  37. package/src/enum/defines.ts +0 -45
  38. package/src/enum/extensions.ts +0 -31
  39. package/src/enum/mod.ts +0 -6
  40. package/src/enum/prelude.ts +0 -619
  41. package/src/enum/symbols.ts +0 -9
  42. package/src/enum/utils.ts +0 -27
  43. package/src/mod.ts +0 -1
package/README.cn.md CHANGED
@@ -1,47 +1,293 @@
1
- # 在 JavaScript 中使用 Rust 特性
1
+ # happy-rusty
2
+
3
+ 将 Rust 的 `Option`、`Result` 和同步原语带入 JavaScript/TypeScript - 更好的错误处理和空值安全模式。
2
4
 
3
5
  [![NPM version](https://img.shields.io/npm/v/happy-rusty.svg)](https://npmjs.org/package/happy-rusty)
4
6
  [![NPM downloads](https://badgen.net/npm/dm/happy-rusty)](https://npmjs.org/package/happy-rusty)
5
7
  [![JSR Version](https://jsr.io/badges/@happy-js/happy-rusty)](https://jsr.io/@happy-js/happy-rusty)
6
8
  [![JSR Score](https://jsr.io/badges/@happy-js/happy-rusty/score)](https://jsr.io/@happy-js/happy-rusty/score)
7
- [![Build Status](https://github.com/jiangjie/happy-rusty/actions/workflows/test.yml/badge.svg)](https://github.com/jiangjie/happy-rusty/actions/workflows/test.yml)
9
+ [![Build Status](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml/badge.svg)](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml)
8
10
  [![codecov](https://codecov.io/gh/JiangJie/happy-rusty/graph/badge.svg)](https://codecov.io/gh/JiangJie/happy-rusty)
9
11
 
10
12
  ---
11
13
 
12
- ## 支持的特性
14
+ [English](README.md)
15
+
16
+ ---
13
17
 
14
- - [Option](https://doc.rust-lang.org/core/option/index.html)
15
- - [Result](https://doc.rust-lang.org/core/result/index.html)
18
+ ## 特性
19
+
20
+ - **Option<T>** - 表示可选值:每个 `Option` 要么是 `Some(T)`,要么是 `None`
21
+ - **Result<T, E>** - 表示成功(`Ok(T)`)或失败(`Err(E)`)
22
+ - **同步原语** - Rust 风格的 `Once<T>`、`Lazy<T>`、`LazyAsync<T>` 和 `Mutex<T>`
23
+ - **控制流** - 用于短路操作的 `ControlFlow<B, C>`,包含 `Break` 和 `Continue`
24
+ - **完整的 TypeScript 支持**,具有严格的类型推断
25
+ - **异步支持** - 所有转换方法都有异步版本
26
+ - **零依赖**
27
+ - **运行时不可变** - 所有实例都通过 `Object.freeze()` 冻结
28
+ - **跨运行时** - 支持 Node.js、Deno、Bun 和浏览器
16
29
 
17
30
  ## 安装
18
31
 
19
32
  ```sh
20
- # via pnpm
21
- pnpm add happy-rusty
22
- # or via yarn
33
+ # npm
34
+ npm install happy-rusty
35
+
36
+ # yarn
23
37
  yarn add happy-rusty
24
- # or just from npm
25
- npm install --save happy-rusty
26
- # via JSR
27
- jsr add @happy-js/happy-rusty
28
- # for deno
38
+
39
+ # pnpm
40
+ pnpm add happy-rusty
41
+
42
+ # JSR (Deno)
29
43
  deno add @happy-js/happy-rusty
30
- # for bun
44
+
45
+ # JSR (Bun)
31
46
  bunx jsr add @happy-js/happy-rusty
32
47
  ```
33
48
 
34
- 接下来就可以在代码里引用了。
49
+ ## 快速开始
35
50
 
36
51
  ```ts
37
52
  import { Some, None, Ok, Err } from 'happy-rusty';
53
+
54
+ // Option - 处理可空值
55
+ function findUser(id: number): Option<User> {
56
+ const user = database.get(id);
57
+ return user ? Some(user) : None;
58
+ }
59
+
60
+ const user = findUser(1)
61
+ .map(u => u.name)
62
+ .unwrapOr('Guest');
63
+
64
+ // Result - 处理错误
65
+ function parseJSON<T>(json: string): Result<T, Error> {
66
+ try {
67
+ return Ok(JSON.parse(json));
68
+ } catch (e) {
69
+ return Err(e as Error);
70
+ }
71
+ }
72
+
73
+ const config = parseJSON<Config>(jsonStr)
74
+ .map(c => c.settings)
75
+ .unwrapOrElse(err => {
76
+ console.error('解析失败:', err);
77
+ return defaultSettings;
78
+ });
79
+ ```
80
+
81
+ ## API 概览
82
+
83
+ ### Option&lt;T&gt;
84
+
85
+ | 分类 | 方法 |
86
+ |------|------|
87
+ | **构造器** | `Some(value)`, `None` |
88
+ | **查询** | `isSome()`, `isNone()`, `isSomeAnd(fn)` |
89
+ | **提取** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |
90
+ | **转换** | `map(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `filter(fn)`, `flatten()` |
91
+ | **布尔操作** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)`, `xor(other)` |
92
+ | **类型转换** | `okOr(err)`, `okOrElse(fn)`, `transpose()` |
93
+ | **组合** | `zip(other)`, `zipWith(other, fn)`, `unzip()` |
94
+ | **副作用** | `inspect(fn)` |
95
+ | **比较** | `eq(other)` |
96
+
97
+ ### Result&lt;T, E&gt;
98
+
99
+ | 分类 | 方法 |
100
+ |------|------|
101
+ | **构造器** | `Ok(value)`, `Ok()` (void), `Err(error)` |
102
+ | **查询** | `isOk()`, `isErr()`, `isOkAnd(fn)`, `isErrAnd(fn)` |
103
+ | **提取 Ok** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |
104
+ | **提取 Err** | `expectErr(msg)`, `unwrapErr()` |
105
+ | **转换** | `map(fn)`, `mapErr(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `flatten()` |
106
+ | **布尔操作** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)` |
107
+ | **类型转换** | `ok()`, `err()`, `transpose()` |
108
+ | **类型断言** | `asOk<F>()`, `asErr<U>()` |
109
+ | **副作用** | `inspect(fn)`, `inspectErr(fn)` |
110
+ | **比较** | `eq(other)` |
111
+
112
+ ### 异步方法
113
+
114
+ 所有转换方法都有带 `Async` 后缀的异步变体:
115
+
116
+ ```ts
117
+ // 异步 Option 方法
118
+ isSomeAndAsync(asyncFn)
119
+ unwrapOrElseAsync(asyncFn)
120
+ andThenAsync(asyncFn)
121
+ orElseAsync(asyncFn)
122
+
123
+ // 异步 Result 方法
124
+ isOkAndAsync(asyncFn)
125
+ isErrAndAsync(asyncFn)
126
+ unwrapOrElseAsync(asyncFn)
127
+ andThenAsync(asyncFn)
128
+ orElseAsync(asyncFn)
38
129
  ```
39
130
 
40
- ## [示例](examples/main.ts)
131
+ ### 类型别名
132
+
133
+ ```ts
134
+ // 常用模式的便捷类型别名
135
+ type AsyncOption<T> = Promise<Option<T>>;
136
+ type AsyncResult<T, E> = Promise<Result<T, E>>;
41
137
 
42
- - [Option](examples/option.ts)
138
+ // 用于 I/O 操作
139
+ type IOResult<T> = Result<T, Error>;
140
+ type AsyncIOResult<T> = Promise<IOResult<T>>;
141
+
142
+ // 用于 void 返回值
143
+ type VoidResult<E> = Result<void, E>;
144
+ type VoidIOResult = IOResult<void>;
145
+ type AsyncVoidResult<E> = Promise<VoidResult<E>>;
146
+ type AsyncVoidIOResult = Promise<VoidIOResult>;
147
+ ```
148
+
149
+ ### 工具函数
150
+
151
+ ```ts
152
+ import { isOption, isResult, isControlFlow, promiseToAsyncResult } from 'happy-rusty';
153
+
154
+ // 类型守卫
155
+ if (isOption(value)) { /* ... */ }
156
+ if (isResult(value)) { /* ... */ }
157
+ if (isControlFlow(value)) { /* ... */ }
158
+
159
+ // 将 Promise 转换为 Result
160
+ const result = await promiseToAsyncResult(fetch('/api/data'));
161
+ result.inspect(data => console.log(data))
162
+ .inspectErr(err => console.error(err));
163
+ ```
164
+
165
+ ### 常量
166
+
167
+ ```ts
168
+ import { RESULT_TRUE, RESULT_FALSE, RESULT_ZERO, RESULT_VOID } from 'happy-rusty';
169
+
170
+ // 可复用的不可变 Result 常量
171
+ function validate(): Result<boolean, Error> {
172
+ return isValid ? RESULT_TRUE : RESULT_FALSE;
173
+ }
174
+
175
+ function doSomething(): Result<void, Error> {
176
+ // ...
177
+ return RESULT_VOID;
178
+ }
179
+ ```
180
+
181
+ ### 同步原语
182
+
183
+ ```ts
184
+ import { Once, Lazy, LazyAsync, Mutex } from 'happy-rusty';
185
+
186
+ // Once - 一次性初始化(类似 Rust 的 OnceLock)
187
+ const config = Once<Config>();
188
+ config.set(loadConfig()); // 只能设置一次
189
+ config.get(); // Some(config) 或 None
190
+ config.getOrInit(() => defaultCfg); // 获取或初始化
191
+
192
+ // Lazy - 惰性初始化,在构造时提供初始化函数
193
+ const expensive = Lazy(() => computeExpensiveValue());
194
+ expensive.force(); // 首次访问时计算,之后缓存
195
+
196
+ // LazyAsync - 异步惰性初始化
197
+ const db = LazyAsync(async () => await Database.connect(url));
198
+ await db.force(); // 只建立一次连接,并发调用会等待
199
+
200
+ // Mutex - 异步互斥锁
201
+ const state = Mutex({ count: 0 });
202
+ await state.withLock(async (s) => {
203
+ s.count += 1; // 独占访问
204
+ });
205
+ ```
206
+
207
+ ### 控制流
208
+
209
+ ```ts
210
+ import { Break, Continue, ControlFlow } from 'happy-rusty';
211
+
212
+ // 短路操作
213
+ function findFirst<T>(arr: T[], pred: (t: T) => boolean): Option<T> {
214
+ for (const item of arr) {
215
+ const flow = pred(item) ? Break(item) : Continue();
216
+ if (flow.isBreak()) {
217
+ return Some(flow.breakValue().unwrap());
218
+ }
219
+ }
220
+ return None;
221
+ }
222
+
223
+ // 带提前退出的自定义 fold
224
+ function tryFold<T, Acc>(
225
+ arr: T[],
226
+ init: Acc,
227
+ f: (acc: Acc, item: T) => ControlFlow<Acc, Acc>
228
+ ): Acc {
229
+ let acc = init;
230
+ for (const item of arr) {
231
+ const flow = f(acc, item);
232
+ if (flow.isBreak()) return flow.breakValue().unwrap();
233
+ acc = flow.continueValue().unwrap();
234
+ }
235
+ return acc;
236
+ }
237
+ ```
238
+
239
+ ## 示例
240
+
241
+ - [Option 基础用法](examples/option.ts)
43
242
  - [AsyncOption](examples/option.async.ts)
44
- - [Result](examples/result.ts)
243
+ - [Result 基础用法](examples/result.ts)
45
244
  - [AsyncResult](examples/result.async.ts)
245
+ - [Once](examples/once.ts)
246
+ - [Lazy](examples/lazy.ts)
247
+ - [Mutex](examples/mutex.ts)
248
+ - [ControlFlow](examples/control_flow.ts)
249
+
250
+ ## 文档
251
+
252
+ 完整的 API 文档请查看 [jiangjie.github.io/happy-rusty](https://jiangjie.github.io/happy-rusty/)。
253
+
254
+ ## 设计说明
255
+
256
+ ### 不可变性
257
+
258
+ 所有类型(`Option`、`Result`、`ControlFlow`、`Lazy`、`LazyAsync`、`Once`、`Mutex`、`MutexGuard`)都通过 `Object.freeze()` 实现**运行时不可变**。这可以防止意外修改方法或属性:
259
+
260
+ ```ts
261
+ const some = Some(42);
262
+ some.unwrap = () => 0; // TypeError: Cannot assign to read only property
263
+ ```
264
+
265
+ **为什么 TypeScript 接口没有使用 `readonly`?**
266
+
267
+ 我们有意在接口的方法签名中省略了 `readonly` 修饰符。虽然这看起来可能会降低类型安全性,但有以下几个原因:
268
+
269
+ 1. **继承兼容性** - `None` 类型继承自 `Option<never>`。TypeScript 的箭头函数属性语法(`readonly prop: () => T`)使用逆变参数检查,这会导致 `None`(参数为 `never`)与 `Option<T>` 不兼容。方法语法(`method(): T`)使用双变参数检查,使继承能够正常工作。
270
+
271
+ 2. **运行时保护已足够** - `Object.freeze()` 已经在运行时阻止了重新赋值。添加 `readonly` 只提供编译时检查,在已有运行时保护的情况下收益有限。
272
+
273
+ 3. **更简洁的 API** - 避免使用 `Mutable*` + `Readonly<>` 模式可以保持导出类型的简洁和文档的可读性。
274
+
275
+ 4. **测试验证不可变性** - 我们的测试套件明确验证了所有实例都被冻结并且会拒绝属性修改。
276
+
277
+ ## 为什么选择 happy-rusty?
278
+
279
+ JavaScript 的 `null`/`undefined` 和 try-catch 模式会导致:
280
+ - 未捕获的空引用错误
281
+ - 遗忘的错误处理
282
+ - 冗长的 try-catch 代码块
283
+ - 不清晰的函数契约
284
+
285
+ `happy-rusty` 提供了 Rust 久经考验的模式:
286
+ - **显式可选性** - `Option<T>` 在类型中明确表示值的缺失
287
+ - **显式错误** - `Result<T, E>` 强制考虑错误处理
288
+ - **链式调用** - 无需嵌套 if-else 或 try-catch 即可转换值
289
+ - **类型安全** - 完整的 TypeScript 支持,具有严格的类型推断
290
+
291
+ ## 许可证
46
292
 
47
- ## [文档](docs/README.md)
293
+ [MIT](LICENSE)
package/README.md CHANGED
@@ -1,53 +1,293 @@
1
- # Use Rust features in JavaScript happily
1
+ # happy-rusty
2
+
3
+ Rust's `Option`, `Result`, and sync primitives for JavaScript/TypeScript - Better error handling and null-safety patterns.
2
4
 
3
5
  [![NPM version](https://img.shields.io/npm/v/happy-rusty.svg)](https://npmjs.org/package/happy-rusty)
4
6
  [![NPM downloads](https://badgen.net/npm/dm/happy-rusty)](https://npmjs.org/package/happy-rusty)
5
7
  [![JSR Version](https://jsr.io/badges/@happy-js/happy-rusty)](https://jsr.io/@happy-js/happy-rusty)
6
8
  [![JSR Score](https://jsr.io/badges/@happy-js/happy-rusty/score)](https://jsr.io/@happy-js/happy-rusty/score)
7
- [![Build Status](https://github.com/jiangjie/happy-rusty/actions/workflows/test.yml/badge.svg)](https://github.com/jiangjie/happy-rusty/actions/workflows/test.yml)
9
+ [![Build Status](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml/badge.svg)](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml)
8
10
  [![codecov](https://codecov.io/gh/JiangJie/happy-rusty/graph/badge.svg)](https://codecov.io/gh/JiangJie/happy-rusty)
9
11
 
10
12
  ---
11
13
 
12
- ## [中文](README.cn.md)
14
+ [中文](README.cn.md)
13
15
 
14
16
  ---
15
17
 
16
- ## Supported
18
+ ## Features
17
19
 
18
- - [Option](https://doc.rust-lang.org/core/option/index.html)
19
- - [Result](https://doc.rust-lang.org/core/result/index.html)
20
+ - **Option&lt;T&gt;** - Represents an optional value: every `Option` is either `Some(T)` or `None`
21
+ - **Result&lt;T, E&gt;** - Represents either success (`Ok(T)`) or failure (`Err(E)`)
22
+ - **Sync Primitives** - Rust-inspired `Once<T>`, `Lazy<T>`, `LazyAsync<T>`, and `Mutex<T>`
23
+ - **Control Flow** - `ControlFlow<B, C>` with `Break` and `Continue` for short-circuiting operations
24
+ - **Full TypeScript support** with strict type inference
25
+ - **Async support** - Async versions of all transformation methods
26
+ - **Zero dependencies**
27
+ - **Runtime immutability** - All instances are frozen with `Object.freeze()`
28
+ - **Cross-runtime** - Works in Node.js, Deno, Bun, and browsers
20
29
 
21
30
  ## Installation
22
31
 
23
32
  ```sh
24
- # via pnpm
25
- pnpm add happy-rusty
26
- # or via yarn
33
+ # npm
34
+ npm install happy-rusty
35
+
36
+ # yarn
27
37
  yarn add happy-rusty
28
- # or just from npm
29
- npm install --save happy-rusty
30
- # via JSR
31
- jsr add @happy-js/happy-rusty
32
- # for deno
38
+
39
+ # pnpm
40
+ pnpm add happy-rusty
41
+
42
+ # JSR (Deno)
33
43
  deno add @happy-js/happy-rusty
34
- # for bun
44
+
45
+ # JSR (Bun)
35
46
  bunx jsr add @happy-js/happy-rusty
36
47
  ```
37
48
 
38
- then import to your code.
49
+ ## Quick Start
39
50
 
40
51
  ```ts
41
52
  import { Some, None, Ok, Err } from 'happy-rusty';
53
+
54
+ // Option - handling nullable values
55
+ function findUser(id: number): Option<User> {
56
+ const user = database.get(id);
57
+ return user ? Some(user) : None;
58
+ }
59
+
60
+ const user = findUser(1)
61
+ .map(u => u.name)
62
+ .unwrapOr('Guest');
63
+
64
+ // Result - handling errors
65
+ function parseJSON<T>(json: string): Result<T, Error> {
66
+ try {
67
+ return Ok(JSON.parse(json));
68
+ } catch (e) {
69
+ return Err(e as Error);
70
+ }
71
+ }
72
+
73
+ const config = parseJSON<Config>(jsonStr)
74
+ .map(c => c.settings)
75
+ .unwrapOrElse(err => {
76
+ console.error('Parse failed:', err);
77
+ return defaultSettings;
78
+ });
79
+ ```
80
+
81
+ ## API Overview
82
+
83
+ ### Option&lt;T&gt;
84
+
85
+ | Category | Methods |
86
+ |----------|---------|
87
+ | **Constructors** | `Some(value)`, `None` |
88
+ | **Querying** | `isSome()`, `isNone()`, `isSomeAnd(fn)` |
89
+ | **Extracting** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |
90
+ | **Transforming** | `map(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `filter(fn)`, `flatten()` |
91
+ | **Boolean ops** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)`, `xor(other)` |
92
+ | **Converting** | `okOr(err)`, `okOrElse(fn)`, `transpose()` |
93
+ | **Combining** | `zip(other)`, `zipWith(other, fn)`, `unzip()` |
94
+ | **Side effects** | `inspect(fn)` |
95
+ | **Comparison** | `eq(other)` |
96
+
97
+ ### Result&lt;T, E&gt;
98
+
99
+ | Category | Methods |
100
+ |----------|---------|
101
+ | **Constructors** | `Ok(value)`, `Ok()` (void), `Err(error)` |
102
+ | **Querying** | `isOk()`, `isErr()`, `isOkAnd(fn)`, `isErrAnd(fn)` |
103
+ | **Extracting Ok** | `expect(msg)`, `unwrap()`, `unwrapOr(default)`, `unwrapOrElse(fn)` |
104
+ | **Extracting Err** | `expectErr(msg)`, `unwrapErr()` |
105
+ | **Transforming** | `map(fn)`, `mapErr(fn)`, `mapOr(default, fn)`, `mapOrElse(defaultFn, fn)`, `flatten()` |
106
+ | **Boolean ops** | `and(other)`, `andThen(fn)`, `or(other)`, `orElse(fn)` |
107
+ | **Converting** | `ok()`, `err()`, `transpose()` |
108
+ | **Type casting** | `asOk<F>()`, `asErr<U>()` |
109
+ | **Side effects** | `inspect(fn)`, `inspectErr(fn)` |
110
+ | **Comparison** | `eq(other)` |
111
+
112
+ ### Async Methods
113
+
114
+ All transformation methods have async variants with `Async` suffix:
115
+
116
+ ```ts
117
+ // Async Option methods
118
+ isSomeAndAsync(asyncFn)
119
+ unwrapOrElseAsync(asyncFn)
120
+ andThenAsync(asyncFn)
121
+ orElseAsync(asyncFn)
122
+
123
+ // Async Result methods
124
+ isOkAndAsync(asyncFn)
125
+ isErrAndAsync(asyncFn)
126
+ unwrapOrElseAsync(asyncFn)
127
+ andThenAsync(asyncFn)
128
+ orElseAsync(asyncFn)
129
+ ```
130
+
131
+ ### Type Aliases
132
+
133
+ ```ts
134
+ // Convenient type aliases for common patterns
135
+ type AsyncOption<T> = Promise<Option<T>>;
136
+ type AsyncResult<T, E> = Promise<Result<T, E>>;
137
+
138
+ // For I/O operations
139
+ type IOResult<T> = Result<T, Error>;
140
+ type AsyncIOResult<T> = Promise<IOResult<T>>;
141
+
142
+ // For void returns
143
+ type VoidResult<E> = Result<void, E>;
144
+ type VoidIOResult = IOResult<void>;
145
+ type AsyncVoidResult<E> = Promise<VoidResult<E>>;
146
+ type AsyncVoidIOResult = Promise<VoidIOResult>;
42
147
  ```
43
148
 
44
- Enjoy the happiness.
149
+ ### Utility Functions
150
+
151
+ ```ts
152
+ import { isOption, isResult, isControlFlow, promiseToAsyncResult } from 'happy-rusty';
153
+
154
+ // Type guards
155
+ if (isOption(value)) { /* ... */ }
156
+ if (isResult(value)) { /* ... */ }
157
+ if (isControlFlow(value)) { /* ... */ }
158
+
159
+ // Convert Promise to Result
160
+ const result = await promiseToAsyncResult(fetch('/api/data'));
161
+ result.inspect(data => console.log(data))
162
+ .inspectErr(err => console.error(err));
163
+ ```
164
+
165
+ ### Constants
166
+
167
+ ```ts
168
+ import { RESULT_TRUE, RESULT_FALSE, RESULT_ZERO, RESULT_VOID } from 'happy-rusty';
45
169
 
46
- ## [Examples](examples/main.ts)
170
+ // Reusable immutable Result constants
171
+ function validate(): Result<boolean, Error> {
172
+ return isValid ? RESULT_TRUE : RESULT_FALSE;
173
+ }
47
174
 
48
- - [Option](examples/option.ts)
175
+ function doSomething(): Result<void, Error> {
176
+ // ...
177
+ return RESULT_VOID;
178
+ }
179
+ ```
180
+
181
+ ### Sync Primitives
182
+
183
+ ```ts
184
+ import { Once, Lazy, LazyAsync, Mutex } from 'happy-rusty';
185
+
186
+ // Once - one-time initialization (like Rust's OnceLock)
187
+ const config = Once<Config>();
188
+ config.set(loadConfig()); // Set once
189
+ config.get(); // Some(config) or None
190
+ config.getOrInit(() => defaultCfg); // Get or initialize
191
+
192
+ // Lazy - lazy initialization with initializer at construction
193
+ const expensive = Lazy(() => computeExpensiveValue());
194
+ expensive.force(); // Compute on first access, cached thereafter
195
+
196
+ // LazyAsync - async lazy initialization
197
+ const db = LazyAsync(async () => await Database.connect(url));
198
+ await db.force(); // Only one connection, concurrent calls wait
199
+
200
+ // Mutex - async mutual exclusion
201
+ const state = Mutex({ count: 0 });
202
+ await state.withLock(async (s) => {
203
+ s.count += 1; // Exclusive access
204
+ });
205
+ ```
206
+
207
+ ### Control Flow
208
+
209
+ ```ts
210
+ import { Break, Continue, ControlFlow } from 'happy-rusty';
211
+
212
+ // Short-circuit operations
213
+ function findFirst<T>(arr: T[], pred: (t: T) => boolean): Option<T> {
214
+ for (const item of arr) {
215
+ const flow = pred(item) ? Break(item) : Continue();
216
+ if (flow.isBreak()) {
217
+ return Some(flow.breakValue().unwrap());
218
+ }
219
+ }
220
+ return None;
221
+ }
222
+
223
+ // Custom fold with early exit
224
+ function tryFold<T, Acc>(
225
+ arr: T[],
226
+ init: Acc,
227
+ f: (acc: Acc, item: T) => ControlFlow<Acc, Acc>
228
+ ): Acc {
229
+ let acc = init;
230
+ for (const item of arr) {
231
+ const flow = f(acc, item);
232
+ if (flow.isBreak()) return flow.breakValue().unwrap();
233
+ acc = flow.continueValue().unwrap();
234
+ }
235
+ return acc;
236
+ }
237
+ ```
238
+
239
+ ## Examples
240
+
241
+ - [Option basics](examples/option.ts)
49
242
  - [AsyncOption](examples/option.async.ts)
50
- - [Result](examples/result.ts)
243
+ - [Result basics](examples/result.ts)
51
244
  - [AsyncResult](examples/result.async.ts)
245
+ - [Once](examples/once.ts)
246
+ - [Lazy](examples/lazy.ts)
247
+ - [Mutex](examples/mutex.ts)
248
+ - [ControlFlow](examples/control_flow.ts)
249
+
250
+ ## Documentation
251
+
252
+ Full API documentation is available at [jiangjie.github.io/happy-rusty](https://jiangjie.github.io/happy-rusty/).
253
+
254
+ ## Design Notes
255
+
256
+ ### Immutability
257
+
258
+ All types (`Option`, `Result`, `ControlFlow`, `Lazy`, `LazyAsync`, `Once`, `Mutex`, `MutexGuard`) are **immutable at runtime** via `Object.freeze()`. This prevents accidental modification of methods or properties:
259
+
260
+ ```ts
261
+ const some = Some(42);
262
+ some.unwrap = () => 0; // TypeError: Cannot assign to read only property
263
+ ```
264
+
265
+ **Why no `readonly` in TypeScript interfaces?**
266
+
267
+ We intentionally omit `readonly` modifiers from method signatures in interfaces. While this might seem to reduce type safety, there are compelling reasons:
268
+
269
+ 1. **Inheritance compatibility** - The `None` type extends `Option<never>`. TypeScript's arrow function property syntax (`readonly prop: () => T`) uses contravariant parameter checking, which causes `None` (with `never` parameters) to be incompatible with `Option<T>`. Method syntax (`method(): T`) uses bivariant checking, allowing the inheritance to work correctly.
270
+
271
+ 2. **Runtime protection is sufficient** - `Object.freeze()` already prevents reassignment at runtime. Adding `readonly` only provides compile-time checking, which offers marginal benefit when runtime protection exists.
272
+
273
+ 3. **Cleaner API** - Avoiding the `Mutable*` + `Readonly<>` pattern keeps the exported types clean and documentation readable.
274
+
275
+ 4. **Testing validates immutability** - Our test suite explicitly verifies that all instances are frozen and reject property modifications.
276
+
277
+ ## Why happy-rusty?
278
+
279
+ JavaScript's `null`/`undefined` and try-catch patterns lead to:
280
+ - Uncaught null reference errors
281
+ - Forgotten error handling
282
+ - Verbose try-catch blocks
283
+ - Unclear function contracts
284
+
285
+ `happy-rusty` provides Rust's battle-tested patterns:
286
+ - **Explicit optionality** - `Option<T>` makes absence visible in types
287
+ - **Explicit errors** - `Result<T, E>` forces error handling consideration
288
+ - **Method chaining** - Transform values without nested if-else or try-catch
289
+ - **Type safety** - Full TypeScript support with strict type inference
290
+
291
+ ## License
52
292
 
53
- ## [Docs](docs/README.md)
293
+ [MIT](LICENSE)