happy-rusty 1.5.0 → 1.6.0
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.
- package/CHANGELOG.md +206 -0
- package/README.cn.md +265 -19
- package/README.md +261 -21
- package/dist/main.cjs +382 -32
- package/dist/main.cjs.map +1 -1
- package/dist/main.mjs +374 -33
- package/dist/main.mjs.map +1 -1
- package/dist/types.d.ts +2002 -52
- package/package.json +37 -24
- package/dist/types.d.ts.map +0 -1
- package/docs/README.md +0 -47
- package/docs/functions/Err.md +0 -46
- package/docs/functions/Ok.md +0 -70
- package/docs/functions/Some.md +0 -45
- package/docs/functions/isOption.md +0 -35
- package/docs/functions/isResult.md +0 -36
- package/docs/functions/promiseToAsyncResult.md +0 -50
- package/docs/interfaces/None.md +0 -979
- package/docs/interfaces/Option.md +0 -857
- package/docs/interfaces/Result.md +0 -903
- package/docs/type-aliases/AsyncIOResult.md +0 -24
- package/docs/type-aliases/AsyncOption.md +0 -24
- package/docs/type-aliases/AsyncResult.md +0 -25
- package/docs/type-aliases/AsyncVoidIOResult.md +0 -17
- package/docs/type-aliases/AsyncVoidResult.md +0 -23
- package/docs/type-aliases/IOResult.md +0 -24
- package/docs/type-aliases/VoidIOResult.md +0 -17
- package/docs/type-aliases/VoidResult.md +0 -23
- package/docs/variables/None.md +0 -18
- package/docs/variables/RESULT_FALSE.md +0 -18
- package/docs/variables/RESULT_TRUE.md +0 -18
- package/docs/variables/RESULT_VOID.md +0 -17
- package/docs/variables/RESULT_ZERO.md +0 -18
- package/src/enum/constants.ts +0 -30
- package/src/enum/core.ts +0 -635
- package/src/enum/defines.ts +0 -45
- package/src/enum/extensions.ts +0 -31
- package/src/enum/mod.ts +0 -6
- package/src/enum/prelude.ts +0 -619
- package/src/enum/symbols.ts +0 -9
- package/src/enum/utils.ts +0 -27
- package/src/mod.ts +0 -1
package/CHANGELOG.md
ADDED
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [1.6.0] - 2025-12-18
|
|
9
|
+
|
|
10
|
+
### Added
|
|
11
|
+
- **Sync Primitives**: `Once<T>`, `Lazy<T>`, `LazyAsync<T>`, `Mutex<T>` for Rust-style synchronization
|
|
12
|
+
- **Control Flow**: `ControlFlow<B, C>` with `Break` and `Continue` variants
|
|
13
|
+
- `Symbol.toStringTag` property to all types for better type identification
|
|
14
|
+
- Custom `toString()` method to all types for debugging
|
|
15
|
+
- `isControlFlow()` type guard utility
|
|
16
|
+
- `isNoneOr()` and `isNoneOrAsync()` methods for Option
|
|
17
|
+
- `exports` field in package.json for modern Node.js module resolution
|
|
18
|
+
- GitHub Pages workflow for automatic API documentation deployment
|
|
19
|
+
- Immutability tests to verify `Object.freeze()` is working correctly
|
|
20
|
+
- 100% test coverage
|
|
21
|
+
- CHANGELOG.md with full version history
|
|
22
|
+
|
|
23
|
+
### Changed
|
|
24
|
+
- All instances are now frozen with `Object.freeze()` for runtime immutability
|
|
25
|
+
- TypeDoc output format from Markdown to HTML for GitHub Pages compatibility
|
|
26
|
+
- Migrated from Deno test to Vitest
|
|
27
|
+
- Build process split into Vite (JS) and Rollup (dts)
|
|
28
|
+
|
|
29
|
+
### Fixed
|
|
30
|
+
- Symbol property syntax and duplicate declaration issues
|
|
31
|
+
- Type inference improvements for `None` interface methods
|
|
32
|
+
|
|
33
|
+
## [1.5.0] - 2024-08-11
|
|
34
|
+
|
|
35
|
+
### Added
|
|
36
|
+
- Async versions of methods: `isSomeAndAsync`, `isOkAndAsync`, `isErrAndAsync`, `unwrapOrElseAsync`, `andThenAsync`, `orElseAsync`
|
|
37
|
+
- Async examples
|
|
38
|
+
|
|
39
|
+
### Changed
|
|
40
|
+
- Updated pnpm to v9.7.0
|
|
41
|
+
- Updated ESLint configuration
|
|
42
|
+
|
|
43
|
+
## [1.4.0] - 2024-08-05
|
|
44
|
+
|
|
45
|
+
### Added
|
|
46
|
+
- `Ok()` constructor without arguments (similar to Rust's `Ok(())`)
|
|
47
|
+
- `RESULT_VOID` constant for void Result returns
|
|
48
|
+
- `VoidResult<E>`, `VoidIOResult`, `AsyncVoidResult<E>`, `AsyncVoidIOResult` type aliases
|
|
49
|
+
|
|
50
|
+
## [1.3.2] - 2024-08-04
|
|
51
|
+
|
|
52
|
+
### Changed
|
|
53
|
+
- Renamed `helpers` to `utils`
|
|
54
|
+
- Improved `@example` annotations in JSDoc
|
|
55
|
+
|
|
56
|
+
## [1.3.1] - 2024-08-03
|
|
57
|
+
|
|
58
|
+
### Fixed
|
|
59
|
+
- `map` methods now correctly return new objects instead of mutating
|
|
60
|
+
|
|
61
|
+
### Changed
|
|
62
|
+
- Updated Rollup to v4.20.0
|
|
63
|
+
|
|
64
|
+
## [1.3.0] - 2024-08-01
|
|
65
|
+
|
|
66
|
+
### Added
|
|
67
|
+
- `RESULT_TRUE`, `RESULT_FALSE`, `RESULT_ZERO` constants
|
|
68
|
+
|
|
69
|
+
### Fixed
|
|
70
|
+
- Circular dependency issues
|
|
71
|
+
|
|
72
|
+
### Changed
|
|
73
|
+
- Reorganized code structure
|
|
74
|
+
|
|
75
|
+
## [1.2.0] - 2024-08-01
|
|
76
|
+
|
|
77
|
+
### Added
|
|
78
|
+
- `isOption()` and `isResult()` type guard utilities
|
|
79
|
+
- Custom string conversion for Option and Result
|
|
80
|
+
|
|
81
|
+
### Changed
|
|
82
|
+
- Replaced arrow functions with normal functions for better debug experience
|
|
83
|
+
- Updated ESLint to v9
|
|
84
|
+
|
|
85
|
+
## [1.1.2] - 2024-07-17
|
|
86
|
+
|
|
87
|
+
### Added
|
|
88
|
+
- `asOk<F>()` and `asErr<U>()` methods for type casting
|
|
89
|
+
|
|
90
|
+
## [1.1.1] - 2024-07-13
|
|
91
|
+
|
|
92
|
+
### Fixed
|
|
93
|
+
- TypeDoc configuration issues
|
|
94
|
+
|
|
95
|
+
### Changed
|
|
96
|
+
- Updated dependencies
|
|
97
|
+
|
|
98
|
+
## [1.1.0] - 2024-06-09
|
|
99
|
+
|
|
100
|
+
### Added
|
|
101
|
+
- `Option.filter()` method
|
|
102
|
+
- Many new Option and Result APIs
|
|
103
|
+
- Comprehensive code comments and documentation
|
|
104
|
+
|
|
105
|
+
### Changed
|
|
106
|
+
- Improved type inference
|
|
107
|
+
- `Option.filter()` now returns `Option<T>` instead of boolean
|
|
108
|
+
|
|
109
|
+
## [1.0.9] - 2024-05-14
|
|
110
|
+
|
|
111
|
+
### Added
|
|
112
|
+
- Documentation for exported symbols
|
|
113
|
+
- README examples
|
|
114
|
+
|
|
115
|
+
## [1.0.8] - 2024-05-13
|
|
116
|
+
|
|
117
|
+
### Changed
|
|
118
|
+
- Switched from npm to pnpm
|
|
119
|
+
- Added GitHub Actions test workflow with Codecov
|
|
120
|
+
|
|
121
|
+
## [1.0.7] - 2024-05-08
|
|
122
|
+
|
|
123
|
+
### Changed
|
|
124
|
+
- `Some` value type changed to `NonNullable<T>`
|
|
125
|
+
|
|
126
|
+
### Fixed
|
|
127
|
+
- Can now invoke `err()` from `Ok` variant
|
|
128
|
+
|
|
129
|
+
## [1.0.6] - 2024-05-08
|
|
130
|
+
|
|
131
|
+
### Added
|
|
132
|
+
- Commonly used type exports
|
|
133
|
+
|
|
134
|
+
### Changed
|
|
135
|
+
- Set `type: "module"` in package.json
|
|
136
|
+
- Build target set to ESNext
|
|
137
|
+
|
|
138
|
+
## [1.0.5] - 2024-05-05
|
|
139
|
+
|
|
140
|
+
### Changed
|
|
141
|
+
- Throw `TypeError` instead of generic `Error`
|
|
142
|
+
- Switched to Rollup for building
|
|
143
|
+
- Added Bun support in CI
|
|
144
|
+
|
|
145
|
+
## [1.0.4] - 2024-05-04
|
|
146
|
+
|
|
147
|
+
### Added
|
|
148
|
+
- Chinese README (`README.cn.md`)
|
|
149
|
+
- JSR publishing workflow
|
|
150
|
+
- npm publishing workflows
|
|
151
|
+
|
|
152
|
+
### Changed
|
|
153
|
+
- Replaced Parcel with Rollup for building
|
|
154
|
+
- Replaced Jest with Bun test
|
|
155
|
+
|
|
156
|
+
## [1.0.3] - 2024-04-27
|
|
157
|
+
|
|
158
|
+
### Added
|
|
159
|
+
- Installation and Examples sections in README
|
|
160
|
+
|
|
161
|
+
### Changed
|
|
162
|
+
- Force return const for better type inference
|
|
163
|
+
|
|
164
|
+
## [1.0.2] - 2024-04-26
|
|
165
|
+
|
|
166
|
+
### Added
|
|
167
|
+
- JSR publishing support
|
|
168
|
+
|
|
169
|
+
### Changed
|
|
170
|
+
- Improved code comments
|
|
171
|
+
|
|
172
|
+
## [1.0.1] - 2024-04-26
|
|
173
|
+
|
|
174
|
+
### Changed
|
|
175
|
+
- Replaced enum with const for better tree-shaking
|
|
176
|
+
- Marked package as side-effect free
|
|
177
|
+
|
|
178
|
+
## [1.0.0] - 2024-04-24
|
|
179
|
+
|
|
180
|
+
### Added
|
|
181
|
+
- Initial release
|
|
182
|
+
- `Option<T>` type with `Some` and `None` variants
|
|
183
|
+
- `Result<T, E>` type with `Ok` and `Err` variants
|
|
184
|
+
- Full TypeScript support
|
|
185
|
+
- Comprehensive API matching Rust's Option and Result
|
|
186
|
+
|
|
187
|
+
[1.6.0]: https://github.com/JiangJie/happy-rusty/compare/v1.5.0...v1.6.0
|
|
188
|
+
[1.5.0]: https://github.com/JiangJie/happy-rusty/compare/v1.4.0...v1.5.0
|
|
189
|
+
[1.4.0]: https://github.com/JiangJie/happy-rusty/compare/v1.3.2...v1.4.0
|
|
190
|
+
[1.3.2]: https://github.com/JiangJie/happy-rusty/compare/v1.3.1...v1.3.2
|
|
191
|
+
[1.3.1]: https://github.com/JiangJie/happy-rusty/compare/v1.3.0...v1.3.1
|
|
192
|
+
[1.3.0]: https://github.com/JiangJie/happy-rusty/compare/v1.2.0...v1.3.0
|
|
193
|
+
[1.2.0]: https://github.com/JiangJie/happy-rusty/compare/v1.1.2...v1.2.0
|
|
194
|
+
[1.1.2]: https://github.com/JiangJie/happy-rusty/compare/v1.1.1...v1.1.2
|
|
195
|
+
[1.1.1]: https://github.com/JiangJie/happy-rusty/compare/v1.1.0...v1.1.1
|
|
196
|
+
[1.1.0]: https://github.com/JiangJie/happy-rusty/compare/v1.0.9...v1.1.0
|
|
197
|
+
[1.0.9]: https://github.com/JiangJie/happy-rusty/compare/v1.0.8...v1.0.9
|
|
198
|
+
[1.0.8]: https://github.com/JiangJie/happy-rusty/compare/v1.0.7...v1.0.8
|
|
199
|
+
[1.0.7]: https://github.com/JiangJie/happy-rusty/compare/v1.0.6...v1.0.7
|
|
200
|
+
[1.0.6]: https://github.com/JiangJie/happy-rusty/compare/v1.0.5...v1.0.6
|
|
201
|
+
[1.0.5]: https://github.com/JiangJie/happy-rusty/compare/v1.0.4...v1.0.5
|
|
202
|
+
[1.0.4]: https://github.com/JiangJie/happy-rusty/compare/v1.0.3...v1.0.4
|
|
203
|
+
[1.0.3]: https://github.com/JiangJie/happy-rusty/compare/v1.0.2...v1.0.3
|
|
204
|
+
[1.0.2]: https://github.com/JiangJie/happy-rusty/compare/v1.0.1...v1.0.2
|
|
205
|
+
[1.0.1]: https://github.com/JiangJie/happy-rusty/compare/v1.0.0...v1.0.1
|
|
206
|
+
[1.0.0]: https://github.com/JiangJie/happy-rusty/releases/tag/v1.0.0
|
package/README.cn.md
CHANGED
|
@@ -1,47 +1,293 @@
|
|
|
1
|
-
#
|
|
1
|
+
# happy-rusty
|
|
2
|
+
|
|
3
|
+
将 Rust 的 `Option`、`Result` 和同步原语带入 JavaScript/TypeScript - 更好的错误处理和空值安全模式。
|
|
2
4
|
|
|
3
5
|
[](https://npmjs.org/package/happy-rusty)
|
|
4
6
|
[](https://npmjs.org/package/happy-rusty)
|
|
5
7
|
[](https://jsr.io/@happy-js/happy-rusty)
|
|
6
8
|
[](https://jsr.io/@happy-js/happy-rusty/score)
|
|
7
|
-
[](https://github.com/JiangJie/happy-rusty/actions/workflows/test.yml)
|
|
8
10
|
[](https://codecov.io/gh/JiangJie/happy-rusty)
|
|
9
11
|
|
|
10
12
|
---
|
|
11
13
|
|
|
12
|
-
|
|
14
|
+
[English](README.md)
|
|
15
|
+
|
|
16
|
+
---
|
|
13
17
|
|
|
14
|
-
|
|
15
|
-
|
|
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
|
-
#
|
|
21
|
-
|
|
22
|
-
|
|
33
|
+
# npm
|
|
34
|
+
npm install happy-rusty
|
|
35
|
+
|
|
36
|
+
# yarn
|
|
23
37
|
yarn add happy-rusty
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
#
|
|
38
|
+
|
|
39
|
+
# pnpm
|
|
40
|
+
pnpm add happy-rusty
|
|
41
|
+
|
|
42
|
+
# JSR (Deno)
|
|
29
43
|
deno add @happy-js/happy-rusty
|
|
30
|
-
|
|
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<T>
|
|
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<T, E>
|
|
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
|
-
|
|
131
|
+
### 类型别名
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
// 常用模式的便捷类型别名
|
|
135
|
+
type AsyncOption<T> = Promise<Option<T>>;
|
|
136
|
+
type AsyncResult<T, E> = Promise<Result<T, E>>;
|
|
41
137
|
|
|
42
|
-
|
|
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
|
-
|
|
293
|
+
[GPL-3.0](LICENSE)
|