@planet-matrix/mobius-model 0.5.0 → 0.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 +24 -0
- package/README.md +123 -36
- package/dist/index.js +45 -4
- package/dist/index.js.map +183 -11
- package/oxlint.config.ts +6 -0
- package/package.json +16 -10
- package/src/abort/README.md +92 -0
- package/src/abort/abort-manager.ts +278 -0
- package/src/abort/abort-signal-listener-manager.ts +81 -0
- package/src/abort/index.ts +2 -0
- package/src/basic/README.md +69 -118
- package/src/basic/function.ts +81 -62
- package/src/basic/is.ts +152 -71
- package/src/basic/promise.ts +29 -8
- package/src/basic/string.ts +2 -33
- package/src/color/README.md +105 -0
- package/src/color/index.ts +3 -0
- package/src/color/internal.ts +42 -0
- package/src/color/rgb/analyze.ts +236 -0
- package/src/color/rgb/construct.ts +130 -0
- package/src/color/rgb/convert.ts +227 -0
- package/src/color/rgb/derive.ts +303 -0
- package/src/color/rgb/index.ts +6 -0
- package/src/color/rgb/internal.ts +208 -0
- package/src/color/rgb/parse.ts +302 -0
- package/src/color/rgb/serialize.ts +144 -0
- package/src/color/types.ts +57 -0
- package/src/color/xyz/analyze.ts +80 -0
- package/src/color/xyz/construct.ts +19 -0
- package/src/color/xyz/convert.ts +71 -0
- package/src/color/xyz/index.ts +3 -0
- package/src/color/xyz/internal.ts +23 -0
- package/src/css/README.md +93 -0
- package/src/css/class.ts +559 -0
- package/src/css/index.ts +1 -0
- package/src/encoding/README.md +66 -79
- package/src/encoding/base64.ts +13 -4
- package/src/environment/README.md +97 -0
- package/src/environment/basic.ts +26 -0
- package/src/environment/device.ts +311 -0
- package/src/environment/feature.ts +285 -0
- package/src/environment/geo.ts +337 -0
- package/src/environment/index.ts +7 -0
- package/src/environment/runtime.ts +400 -0
- package/src/environment/snapshot.ts +60 -0
- package/src/environment/variable.ts +239 -0
- package/src/event/README.md +90 -0
- package/src/event/class-event-proxy.ts +228 -0
- package/src/event/common.ts +19 -0
- package/src/event/event-manager.ts +203 -0
- package/src/event/index.ts +4 -0
- package/src/event/instance-event-proxy.ts +186 -0
- package/src/event/internal.ts +24 -0
- package/src/exception/README.md +96 -0
- package/src/exception/browser.ts +219 -0
- package/src/exception/index.ts +4 -0
- package/src/exception/nodejs.ts +169 -0
- package/src/exception/normalize.ts +106 -0
- package/src/exception/types.ts +99 -0
- package/src/identifier/README.md +92 -0
- package/src/identifier/id.ts +119 -0
- package/src/identifier/index.ts +2 -0
- package/src/identifier/uuid.ts +187 -0
- package/src/index.ts +16 -1
- package/src/log/README.md +79 -0
- package/src/log/index.ts +5 -0
- package/src/log/log-emitter.ts +72 -0
- package/src/log/log-record.ts +10 -0
- package/src/log/log-scheduler.ts +74 -0
- package/src/log/log-type.ts +8 -0
- package/src/log/logger.ts +543 -0
- package/src/orchestration/README.md +89 -0
- package/src/orchestration/coordination/barrier.ts +214 -0
- package/src/orchestration/coordination/count-down-latch.ts +215 -0
- package/src/orchestration/coordination/errors.ts +98 -0
- package/src/orchestration/coordination/index.ts +16 -0
- package/src/orchestration/coordination/internal/wait-constraints.ts +95 -0
- package/src/orchestration/coordination/internal/wait-queue.ts +109 -0
- package/src/orchestration/coordination/keyed-lock.ts +168 -0
- package/src/orchestration/coordination/mutex.ts +257 -0
- package/src/orchestration/coordination/permit.ts +127 -0
- package/src/orchestration/coordination/read-write-lock.ts +444 -0
- package/src/orchestration/coordination/semaphore.ts +280 -0
- package/src/orchestration/index.ts +1 -0
- package/src/random/README.md +55 -86
- package/src/random/index.ts +1 -1
- package/src/random/string.ts +35 -0
- package/src/reactor/README.md +4 -0
- package/src/reactor/reactor-core/primitive.ts +9 -9
- package/src/reactor/reactor-core/reactive-system.ts +5 -5
- package/src/singleton/README.md +79 -0
- package/src/singleton/factory.ts +55 -0
- package/src/singleton/index.ts +2 -0
- package/src/singleton/manager.ts +204 -0
- package/src/storage/README.md +107 -0
- package/src/storage/index.ts +1 -0
- package/src/storage/table.ts +449 -0
- package/src/timer/README.md +86 -0
- package/src/timer/expiration/expiration-manager.ts +594 -0
- package/src/timer/expiration/index.ts +3 -0
- package/src/timer/expiration/min-heap.ts +208 -0
- package/src/timer/expiration/remaining-manager.ts +241 -0
- package/src/timer/index.ts +1 -0
- package/src/type/README.md +54 -307
- package/src/type/class.ts +2 -2
- package/src/type/index.ts +14 -14
- package/src/type/is.ts +265 -2
- package/src/type/object.ts +37 -0
- package/src/type/string.ts +7 -2
- package/src/type/tuple.ts +6 -6
- package/src/type/union.ts +16 -0
- package/src/web/README.md +77 -0
- package/src/web/capture.ts +35 -0
- package/src/web/clipboard.ts +97 -0
- package/src/web/dom.ts +117 -0
- package/src/web/download.ts +16 -0
- package/src/web/event.ts +46 -0
- package/src/web/index.ts +10 -0
- package/src/web/local-storage.ts +113 -0
- package/src/web/location.ts +28 -0
- package/src/web/permission.ts +172 -0
- package/src/web/script-loader.ts +432 -0
- package/tests/unit/abort/abort-manager.spec.ts +225 -0
- package/tests/unit/abort/abort-signal-listener-manager.spec.ts +62 -0
- package/tests/unit/basic/array.spec.ts +1 -1
- package/tests/unit/basic/stream.spec.ts +1 -1
- package/tests/unit/basic/string.spec.ts +0 -9
- package/tests/unit/color/rgb/analyze.spec.ts +110 -0
- package/tests/unit/color/rgb/construct.spec.ts +56 -0
- package/tests/unit/color/rgb/convert.spec.ts +60 -0
- package/tests/unit/color/rgb/derive.spec.ts +103 -0
- package/tests/unit/color/rgb/parse.spec.ts +66 -0
- package/tests/unit/color/rgb/serialize.spec.ts +46 -0
- package/tests/unit/color/xyz/analyze.spec.ts +33 -0
- package/tests/unit/color/xyz/construct.spec.ts +10 -0
- package/tests/unit/color/xyz/convert.spec.ts +18 -0
- package/tests/unit/css/class.spec.ts +157 -0
- package/tests/unit/environment/basic.spec.ts +20 -0
- package/tests/unit/environment/device.spec.ts +146 -0
- package/tests/unit/environment/feature.spec.ts +388 -0
- package/tests/unit/environment/geo.spec.ts +111 -0
- package/tests/unit/environment/runtime.spec.ts +364 -0
- package/tests/unit/environment/snapshot.spec.ts +4 -0
- package/tests/unit/environment/variable.spec.ts +190 -0
- package/tests/unit/event/class-event-proxy.spec.ts +225 -0
- package/tests/unit/event/event-manager.spec.ts +246 -0
- package/tests/unit/event/instance-event-proxy.spec.ts +187 -0
- package/tests/unit/exception/browser.spec.ts +213 -0
- package/tests/unit/exception/nodejs.spec.ts +144 -0
- package/tests/unit/exception/normalize.spec.ts +57 -0
- package/tests/unit/identifier/id.spec.ts +71 -0
- package/tests/unit/identifier/uuid.spec.ts +85 -0
- package/tests/unit/log/log-emitter.spec.ts +33 -0
- package/tests/unit/log/log-scheduler.spec.ts +40 -0
- package/tests/unit/log/log-type.spec.ts +7 -0
- package/tests/unit/log/logger.spec.ts +222 -0
- package/tests/unit/orchestration/coordination/barrier.spec.ts +96 -0
- package/tests/unit/orchestration/coordination/count-down-latch.spec.ts +63 -0
- package/tests/unit/orchestration/coordination/errors.spec.ts +29 -0
- package/tests/unit/orchestration/coordination/keyed-lock.spec.ts +109 -0
- package/tests/unit/orchestration/coordination/mutex.spec.ts +132 -0
- package/tests/unit/orchestration/coordination/permit.spec.ts +43 -0
- package/tests/unit/orchestration/coordination/read-write-lock.spec.ts +154 -0
- package/tests/unit/orchestration/coordination/semaphore.spec.ts +135 -0
- package/tests/unit/random/string.spec.ts +11 -0
- package/tests/unit/reactor/alien-signals-effect.spec.ts +11 -10
- package/tests/unit/reactor/preact-signal.spec.ts +1 -2
- package/tests/unit/singleton/singleton.spec.ts +49 -0
- package/tests/unit/storage/table.spec.ts +620 -0
- package/tests/unit/timer/expiration/expiration-manager.spec.ts +464 -0
- package/tests/unit/timer/expiration/min-heap.spec.ts +71 -0
- package/tests/unit/timer/expiration/remaining-manager.spec.ts +234 -0
- package/.oxlintrc.json +0 -5
- package/src/random/uuid.ts +0 -103
- package/tests/unit/random/uuid.spec.ts +0 -37
package/src/type/README.md
CHANGED
|
@@ -1,330 +1,77 @@
|
|
|
1
1
|
# Type
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
## Description
|
|
4
4
|
|
|
5
|
-
|
|
5
|
+
Type 模块用于提供面向 TypeScript 类型系统(type system)的通用类型建模能力,主要承载类型判断、类型组合、类型转换以及类型结构重塑等公共语义。
|
|
6
6
|
|
|
7
|
-
|
|
7
|
+
它并不是为了堆叠炫技式的类型体操,而是为了沉淀一组能够长期复用、命名稳定、语义清楚的类型层工具。这个模块关注的是“哪些静态约束值得被抽象为基础模型”,而不是让局部实现里的技巧性写法直接变成公共 API。
|
|
8
8
|
|
|
9
|
-
|
|
9
|
+
## For Understanding
|
|
10
10
|
|
|
11
|
-
|
|
12
|
-
2. Is: Generic predicates and basic type guards at the type level.
|
|
13
|
-
3. Union: Utilities for building, filtering, and comparing union types.
|
|
14
|
-
4. Intersection: Utilities for composing and analyzing intersection types.
|
|
15
|
-
5. String: Validation, comparison, queries, slicing, and transformation for string literal types.
|
|
16
|
-
6. Path: Parsing and access helpers for dot-path strings and object path navigation.
|
|
17
|
-
7. Boolean: Logical composition and boolean collection helpers.
|
|
18
|
-
8. Number: Numeric checks, comparisons, arithmetic, and range construction for number literal types.
|
|
19
|
-
9. Object: Key/value queries, structural reshaping, and property-level composition.
|
|
20
|
-
10. Function: Parameter and return extraction, comparisons, and function-shape transformations.
|
|
21
|
-
11. Tuple: Tuple length, element access, mapping, and composition utilities.
|
|
22
|
-
12. Class: Constructor and instance shape helpers for class-based typing.
|
|
23
|
-
13. Iteration: Iterative helpers for building or traversing type-level sequences.
|
|
11
|
+
理解 Type 模块时,应先区分它与运行时工具模块的职责差异。这里解决的问题发生在编译阶段:如何表达约束、如何描述结构关系、如何在类型层提前暴露不合法的使用方式、以及如何把一组复杂条件压缩成更稳定的公共类型语义。
|
|
24
12
|
|
|
25
|
-
|
|
13
|
+
因此,这个模块适合放在公共 API 设计、库封装、复杂配置建模、框架适配和类型推导增强等边界中。只要某个问题的核心是“能否在编译阶段更早发现错误”或“能否把约束用类型表达而不是运行时代码表达”,Type 模块通常就比继续增加运行时判断更合适。
|
|
26
14
|
|
|
27
|
-
|
|
15
|
+
也正因为如此,本模块的边界不应被理解为“所有和 TypeScript 有关的东西”。仅当一个能力表达的是稳定、可复用的类型语义时,它才适合进入这里。某个局部实现专用的类型补丁、只为绕过编译器局限而存在的临时技巧、或者过度依赖当前文件上下文的辅助类型,都不应轻易加入公共导出。
|
|
28
16
|
|
|
29
|
-
|
|
30
|
-
2. Primitives: Core domain-specific primitives and base helpers.
|
|
31
|
-
3. Validation: Presence checks, format checks, and equality checks.
|
|
32
|
-
4. Comparison: Ordering, equality, and compatibility checks.
|
|
33
|
-
5. Query: Length, count, index, and metadata queries.
|
|
34
|
-
6. Generation: Creating new literal values, ranges, or repeated structures.
|
|
35
|
-
7. Extraction: Pulling out segments, first/last elements, or subsets.
|
|
36
|
-
8. Manipulation: Replacing, concatenating, mapping, and transforming shapes.
|
|
37
|
-
9. Conversion: Converting between string/number/boolean or related domains.
|
|
17
|
+
## For Using
|
|
38
18
|
|
|
39
|
-
|
|
19
|
+
当你需要在静态层面表达类型关系,而不是在运行时反复写守卫与转换逻辑时,可以使用这个模块。它适合那些需要提高公共 API 可读性、约束复杂输入结构、维护类型推导结果稳定性、或在库层提供更强静态保证的场景。
|
|
40
20
|
|
|
41
|
-
|
|
21
|
+
从使用角度看,这个模块大致可以分为几类能力。第一类是基础判断与辅助能力,用于表达原始类型、对象、数组、函数、类等常见结构的静态条件。第二类是关系与运算能力,用于处理联合、交叉、字面量、路径等类型之间的组合与转换。第三类是结构重塑能力,用于在对象、数组、元组、函数签名等结构之间做映射、拆分、约束和重组。
|
|
42
22
|
|
|
43
|
-
|
|
23
|
+
更合理的使用方式,是先从你要表达的语义出发,再选取最接近该语义的类型工具,而不是把它们当作纯技巧库随意拼接。只要类型声明开始主要服务于“让编译器刚好不报错”,而不是帮助调用方理解边界,那通常意味着抽象方向已经偏离了这个模块的目标。
|
|
44
24
|
|
|
45
|
-
|
|
25
|
+
## For Contributing
|
|
46
26
|
|
|
47
|
-
|
|
27
|
+
贡献 Type 模块时,应先回答两个问题:新增能力解决的是不是一个可长期复用的类型建模问题,以及它是否能以清楚、稳定、可读的形式向外承诺。只有在这两个问题的答案都足够明确时,一个新类型才值得被公开导出。
|
|
48
28
|
|
|
49
|
-
|
|
29
|
+
在实现层面,应优先保证语义清晰和调用方面向的可读性,再考虑技巧性。复杂递归、分布式条件类型、累加器模式或品牌类型等写法本身并不构成价值;真正的价值在于它们是否帮助调用方稳定地理解某个约束。若一个类型只是在内部为另一个公开类型服务,就应优先把它保留为内部辅助项,而不是公开成新的通用工具。
|
|
50
30
|
|
|
51
|
-
|
|
52
|
-
// ============================================================================
|
|
53
|
-
// Group Name
|
|
54
|
-
// ============================================================================
|
|
55
|
-
```
|
|
31
|
+
### JSDoc 注释格式要求
|
|
56
32
|
|
|
57
|
-
|
|
58
|
-
-
|
|
59
|
-
-
|
|
60
|
-
-
|
|
33
|
+
- 每个公开导出的目标(类型、函数、变量、类等)都应包含 JSDoc 注释,让人在不跳转实现的情况下就能理解用途。
|
|
34
|
+
- JSDoc 注释第一行应为清晰且简洁的描述,该描述优先使用中文(英文也可以)。
|
|
35
|
+
- 如果描述后还有其他内容,应在描述后加一个空行。
|
|
36
|
+
- 如果有示例,应使用 `@example` 标签,后接三重反引号代码块(不带语言标识)。
|
|
37
|
+
- 如果有示例,应包含多个场景,展示不同用法,尤其要覆盖常见组合方式或边界输入。
|
|
38
|
+
- 如果有示例,应使用注释格式说明每个场景:`// Expect: <result>`。
|
|
39
|
+
- 如果有示例,应将结果赋值给 `example1`、`example2` 之类的变量,以保持示例易读。
|
|
40
|
+
- 如果有示例,`// Expect: <result>` 应该位于 `example1`、`example2` 之前,以保持示例的逻辑清晰。
|
|
41
|
+
- 如果有示例,应优先使用确定性示例;避免断言精确的随机输出。
|
|
42
|
+
- 如果函数返回结构化字符串,应展示其预期格式特征。
|
|
43
|
+
- 如果有参考资料,应将 `@see` 放在 `@example` 代码块之后,并用一个空行分隔。
|
|
61
44
|
|
|
62
|
-
|
|
45
|
+
### 实现规范要求
|
|
63
46
|
|
|
64
|
-
|
|
47
|
+
- 不同程序元素之间使用一个空行分隔,保持结构清楚。这里的程序元素,通常指函数、类型、常量,以及直接服务于它们的辅助元素。
|
|
48
|
+
- 某程序元素独占的辅助元素与该程序元素本身视为一个整体,不要在它们之间添加空行。
|
|
49
|
+
- 程序元素的辅助元素应该放置在该程序元素的上方,以保持阅读时的逻辑顺序。
|
|
50
|
+
- 若辅助元素被多个程序元素共享,则应将其视为独立的程序元素,放在这些程序元素中第一个相关目标的上方,并与后续程序元素之间保留一个空行。
|
|
51
|
+
- 辅助元素也应该像其它程序元素一样,保持清晰的命名和适当的注释,以便在需要阅读实现细节时能够快速理解它们的作用和使用方式。
|
|
52
|
+
- 辅助元素的命名必须以前缀 `internal` 开头(或 `Internal`,大小写不敏感)。
|
|
53
|
+
- 辅助元素永远不要公开导出。
|
|
54
|
+
- 被模块内多个不同文件中的程序元素共享的辅助元素,应该放在一个单独的文件中,例如 `./src/type/internal.ts`。
|
|
55
|
+
- 模块内可以包含子模块。只有当某个子目录表达一个稳定、可单独理解、且可能被父模块重导出的子问题域时,才应将其视为子模块。
|
|
56
|
+
- 子模块包含多个文件时,应该为其单独创建子文件夹,并为其创建单独的 Barrel 文件;父模块的 Barrel 文件再重导出子模块的 Barrel 文件。
|
|
57
|
+
- 子模块不需要有自己的 `README.md`。
|
|
58
|
+
- 子模块可以有自己的 `internal.ts` 文件,多个子模块共享的辅助元素应该放在父模块的 `internal.ts` 文件中,单个子模块共享的辅助元素应该放在该子模块的 `internal.ts` 文件中。
|
|
59
|
+
- 对模块依赖关系的要求(通常是不循环依赖或不反向依赖)与对 DRY 的要求可能产生冲突。此时,若复用的代码数量不大,可以适当牺牲 DRY,复制粘贴并保留必要的注释说明;若复用的代码数量较大,则可以将其抽象到新的文件或子模块中,如 `common.ts`,并在需要的地方导入使用。
|
|
60
|
+
- 对复杂条件类型、递归类型、累加器模式或分布式条件类型,应优先让公开 API 保持最小、清晰、稳定的参数面,而不要把内部技巧直接暴露给调用方。
|
|
65
61
|
|
|
66
|
-
|
|
67
|
-
2. Primitives: Types closely related to the module's core types, such as `NumberSign` and `NumberDigitCount` in `Number`, `StringAutoCompletable`, `UppercaseLetter`, `LowercaseLetter`, `DigitCharacter` in `String`, `FunctionNoop`, `FunctionIdentity`, `FunctionConstant` in `Function`, and `TupleEmpty`, `TupleSingleton` in `Tuple`.
|
|
68
|
-
3. Validation: Types for validation or checking, such as `StringIsNumber`, `StringIsAlpha`, `StringIsEmpty`, `StringIsUpperCase` in `String`, `NumberIsZero`, `NumberIsPositive`, `NumberIsNegative`, `NumberIsEven` in `Number`, `FunctionIsAsync` in `Function`, `ClassIsConstructor` in `Class`.
|
|
69
|
-
4. Comparison: Types for comparing values, such as `StringIsEqual`, `StringStartsWith`, `StringEndsWith` in `String`, `NumberIsEqual`, `NumberGreaterThan`, `NumberLessThan` in `Number`, `FunctionParametersEqual` in `Function`, `TupleIsEqual`, `TupleStartsWith`, `TupleEndsWith` in `Tuple`.
|
|
70
|
-
5. Query: Types for querying information without transformation, such as `StringLength`, `StringCount`, `StringIndexOf` in `String`, `FunctionLength`, `FunctionArity` in `Function`, `TupleLength`, `TupleIndexOf` in `Tuple`, and `ClassConstructorArity` in `Class`.
|
|
71
|
-
6. Generation: Types for creating new values from scratch, such as `StringRepeat` in `String`, `TupleRepeat`, `TupleRange`, `TupleCombinations` in `Tuple`.
|
|
72
|
-
7. Extraction: Types for extracting partial content, such as `StringFirst`, `StringLast`, `StringAt` in `String`, `TupleHead`, `TupleTail`, `TupleAt` in `Tuple`.
|
|
73
|
-
8. Manipulation: Types for modifying values, such as `StringTakeFirst`, `StringReplaceAll`, `StringTrim`, `StringSplit`, `StringJoin` in `String`, `NumberAdd`, `NumberSubtract`, `NumberMultiply` in `Number`, `FunctionBind`, `FunctionInsertParameter`, `FunctionRemoveParameter` in `Function`, `ObjectMerge`, `ObjectAssign`, `ObjectOverwrite` in `Object`, and `TupleMap`, `TupleFilter`, `TupleAppend` in `Tuple`.
|
|
74
|
-
9. Conversion: Types for converting between different domains, such as `NumberToString`, `NumberToBoolean` in `Number`, `BooleanToNumber`, `BooleanToString` in `Boolean`, `TupleToUnion`, `TupleToObject`, `TupleToArray`, `TupleToString` in `Tuple`, `UnionToIntersection`, `UnionToTuple` in `Union`, `ObjectToFunction` in `Object`, and `ClassConstructorToFunction` or `FunctionToClassConstructor` in `Class`/`Function`.
|
|
62
|
+
### 导出策略要求
|
|
75
63
|
|
|
76
|
-
|
|
64
|
+
- 保持内部辅助项和内部符号为私有,不要让外部接入依赖临时性的内部结构。
|
|
65
|
+
- 每个模块都应有一个用于重导出所有公共 API 的 Barrel 文件。
|
|
66
|
+
- Barrel 文件应命名为 `index.ts`,放在模块目录根部,并且所有公共 API 都应从该文件导出。
|
|
67
|
+
- 新增公共能力时,应优先检查它是否表达稳定、清楚且值得长期维护的类型语义,而不是某段实现细节的便捷暴露;仅在确认需要长期对外承诺时再加入 Barrel 导出。
|
|
77
68
|
|
|
78
|
-
|
|
69
|
+
### 测试要求
|
|
79
70
|
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
* ```
|
|
88
|
-
* // Expect: <expected result>
|
|
89
|
-
* type Example1 = TypeName<...>
|
|
90
|
-
* // Expect: <expected result>
|
|
91
|
-
* type Example2 = TypeName<...>
|
|
92
|
-
* ```
|
|
93
|
-
*/
|
|
94
|
-
export type TypeName<...> = ...
|
|
95
|
-
```
|
|
96
|
-
|
|
97
|
-
**Documentation Rules:**
|
|
98
|
-
- First line: Clear, concise description starting with a verb (Check, Get, Convert, etc.)
|
|
99
|
-
- Add a blank line after the description
|
|
100
|
-
- Use `@example` tag followed by triple backticks
|
|
101
|
-
- Include multiple example cases showing different scenarios
|
|
102
|
-
- Use comment format: `// Expect: <result>`
|
|
103
|
-
- Use descriptive example names: `Example1`, `Example2`, `Example3`, etc.
|
|
104
|
-
- Include edge cases (empty values, single elements, etc.)
|
|
105
|
-
|
|
106
|
-
#### 2.2 Example Writing Guidelines
|
|
107
|
-
|
|
108
|
-
**Good Examples:**
|
|
109
|
-
```typescript
|
|
110
|
-
/**
|
|
111
|
-
* Check if a string starts with a prefix.
|
|
112
|
-
*
|
|
113
|
-
* @example
|
|
114
|
-
* ```
|
|
115
|
-
* // Expect: true
|
|
116
|
-
* type Example1 = StringStartsWith<'hello world', 'hello'>
|
|
117
|
-
* // Expect: false
|
|
118
|
-
* type Example2 = StringStartsWith<'hello world', 'world'>
|
|
119
|
-
* // Expect: true
|
|
120
|
-
* type Example3 = StringStartsWith<'', ''>
|
|
121
|
-
* ```
|
|
122
|
-
*/
|
|
123
|
-
```
|
|
124
|
-
|
|
125
|
-
**Coverage Priority:**
|
|
126
|
-
1. Typical use case (most common scenario)
|
|
127
|
-
2. Edge cases (empty, single element, boundary conditions)
|
|
128
|
-
3. Negative cases (when the operation fails or returns false)
|
|
129
|
-
4. Complex cases (if applicable)
|
|
130
|
-
|
|
131
|
-
### 3. Type Implementation Patterns
|
|
132
|
-
|
|
133
|
-
#### 3.1 Internal Helper Types
|
|
134
|
-
|
|
135
|
-
When a type requires a complex implementation with accumulator parameters or intermediate state, use an `Internal`-prefixed helper type:
|
|
136
|
-
|
|
137
|
-
```typescript
|
|
138
|
-
// Internal helper type - not exported
|
|
139
|
-
type InternalStringLength<S extends string, Acc extends readonly unknown[]> =
|
|
140
|
-
S extends `${string}${infer Rest}`
|
|
141
|
-
? InternalStringLength<Rest, [...Acc, unknown]>
|
|
142
|
-
: Acc['length']
|
|
143
|
-
|
|
144
|
-
/**
|
|
145
|
-
* Get the length of a string literal type.
|
|
146
|
-
*
|
|
147
|
-
* @example
|
|
148
|
-
* ```
|
|
149
|
-
* // Expect: 5
|
|
150
|
-
* type Example1 = StringLength<'hello'>
|
|
151
|
-
* ```
|
|
152
|
-
*/
|
|
153
|
-
export type StringLength<S extends string> = InternalStringLength<S, []>
|
|
154
|
-
```
|
|
155
|
-
|
|
156
|
-
**Internal Type Rules:**
|
|
157
|
-
- Prefix with `Internal`
|
|
158
|
-
- Do NOT export
|
|
159
|
-
- Define immediately before the public type that uses it
|
|
160
|
-
- NO blank line between the internal helper and the public type
|
|
161
|
-
- Include all implementation details (accumulators, counters, flags)
|
|
162
|
-
- The public API should hide complexity and provide clean, minimal parameters
|
|
163
|
-
|
|
164
|
-
#### 3.2 Recursive Patterns
|
|
165
|
-
|
|
166
|
-
Most type gymnastics use recursion. Common patterns:
|
|
167
|
-
|
|
168
|
-
**Pattern 1: Tail Recursion with Accumulator**
|
|
169
|
-
```typescript
|
|
170
|
-
type InternalReverse<S extends string, Acc extends string = ''> =
|
|
171
|
-
S extends `${infer First}${infer Rest}`
|
|
172
|
-
? InternalReverse<Rest, `${First}${Acc}`>
|
|
173
|
-
: Acc
|
|
174
|
-
```
|
|
175
|
-
|
|
176
|
-
**Pattern 2: Array/Tuple Length as Counter**
|
|
177
|
-
```typescript
|
|
178
|
-
type InternalRepeat<
|
|
179
|
-
S extends string,
|
|
180
|
-
N extends number,
|
|
181
|
-
Acc extends string,
|
|
182
|
-
Count extends readonly unknown[]
|
|
183
|
-
> = Count['length'] extends N
|
|
184
|
-
? Acc
|
|
185
|
-
: InternalRepeat<S, N, `${Acc}${S}`, [...Count, unknown]>
|
|
186
|
-
```
|
|
187
|
-
|
|
188
|
-
**Pattern 3: Distributed Conditional Types**
|
|
189
|
-
```typescript
|
|
190
|
-
type StringSplit<S extends string, Separator extends string> =
|
|
191
|
-
S extends `${infer First}${Separator}${infer Rest}`
|
|
192
|
-
? [First, ...StringSplit<Rest, Separator>]
|
|
193
|
-
: (S extends '' ? [] : [S])
|
|
194
|
-
```
|
|
195
|
-
|
|
196
|
-
**Pattern 4: Type Narrowing with Extends**
|
|
197
|
-
```typescript
|
|
198
|
-
export type BooleanAnd<T extends boolean, U extends boolean> =
|
|
199
|
-
T extends true
|
|
200
|
-
? (U extends true ? true : false)
|
|
201
|
-
: false
|
|
202
|
-
```
|
|
203
|
-
|
|
204
|
-
**Ternary Formatting Rules:**
|
|
205
|
-
|
|
206
|
-
When working with nested conditional types (ternary operations):
|
|
207
|
-
|
|
208
|
-
1. **Single-level ternary**: Can be written inline if simple and readable
|
|
209
|
-
```typescript
|
|
210
|
-
type Simple<T> = T extends string ? true : false
|
|
211
|
-
```
|
|
212
|
-
|
|
213
|
-
2. **Two or more levels of nesting**: **MUST** wrap the second level and beyond in parentheses
|
|
214
|
-
```typescript
|
|
215
|
-
// ✅ Correct - nested ternary wrapped in parentheses
|
|
216
|
-
type Nested<T> =
|
|
217
|
-
T extends string
|
|
218
|
-
? (T extends '' ? 'empty' : 'non-empty')
|
|
219
|
-
: false
|
|
220
|
-
|
|
221
|
-
// ❌ Wrong - missing parentheses on nested ternary
|
|
222
|
-
type Wrong<T> =
|
|
223
|
-
T extends string
|
|
224
|
-
? T extends '' ? 'empty' : 'non-empty'
|
|
225
|
-
: false
|
|
226
|
-
```
|
|
227
|
-
|
|
228
|
-
3. **Line breaks**: If the nested ternary can fit on one line and remain readable, keep it on one line. Only break into multiple lines when it improves clarity for complex expressions.
|
|
229
|
-
|
|
230
|
-
4. **Readability**: If a ternary becomes too complex (3+ levels), consider extracting to helper types
|
|
231
|
-
|
|
232
|
-
This ensures code clarity and makes the nesting structure immediately visible.
|
|
233
|
-
|
|
234
|
-
#### 3.3 Parameter Constraints
|
|
235
|
-
|
|
236
|
-
Always use proper constraints for type parameters:
|
|
237
|
-
|
|
238
|
-
```typescript
|
|
239
|
-
// String operations
|
|
240
|
-
export type StringReverse<S extends string> = ...
|
|
241
|
-
|
|
242
|
-
// Boolean operations
|
|
243
|
-
export type BooleanAnd<T extends boolean, U extends boolean> = ...
|
|
244
|
-
|
|
245
|
-
// Array/Tuple operations
|
|
246
|
-
export type BooleanAll<T extends readonly boolean[]> = ...
|
|
247
|
-
|
|
248
|
-
// Number constraints
|
|
249
|
-
export type StringRepeat<S extends string, N extends number> = ...
|
|
250
|
-
```
|
|
251
|
-
|
|
252
|
-
**Key Points:**
|
|
253
|
-
- Use `extends string`, `extends boolean`, `extends number` for primitive types
|
|
254
|
-
- Use `extends readonly T[]` for immutable arrays/tuples
|
|
255
|
-
- Use `extends unknown` for generic or any type parameters
|
|
256
|
-
- Add default values when appropriate (e.g., `First extends boolean = true`)
|
|
257
|
-
|
|
258
|
-
### 4. Naming Conventions
|
|
259
|
-
|
|
260
|
-
#### 4.1 Type Name Format
|
|
261
|
-
|
|
262
|
-
All types should follow a consistent naming pattern:
|
|
263
|
-
|
|
264
|
-
**Format:** `<Domain><Operation><Qualifier>`
|
|
265
|
-
|
|
266
|
-
- **Domain:** `String`, `Boolean`, `Number`, `Array`, `Object`, `Path`, etc.
|
|
267
|
-
- **Operation:** Verb describing the action (Check, Get, Convert, Split, etc.)
|
|
268
|
-
- **Qualifier:** Optional descriptor (First, Last, All, etc.)
|
|
269
|
-
|
|
270
|
-
**Examples:**
|
|
271
|
-
- `StringSplitToWords` - domain: String, operation: Split, qualifier: ToWords
|
|
272
|
-
- `BooleanCountTrue` - domain: Boolean, operation: Count, qualifier: True
|
|
273
|
-
- `StringIsEmpty` - domain: String, operation: Is, qualifier: Empty
|
|
274
|
-
|
|
275
|
-
#### 4.2 Common Verb Prefixes
|
|
276
|
-
|
|
277
|
-
- `Is*` - Returns boolean for validation or checking
|
|
278
|
-
- Examples: `IsEmpty`, `IsNumber`, `IsAlpha`, `IsEqual`
|
|
279
|
-
- `Has*` - Returns boolean for existence checking
|
|
280
|
-
- Examples: `HasPrefix`, `HasSuffix`
|
|
281
|
-
- `Get*` / `Extract*` - Returns a value
|
|
282
|
-
- Examples: `GetFirst`, `ExtractGroups`
|
|
283
|
-
- `String*` / `Boolean*` / etc. - Domain-scoped operations
|
|
284
|
-
- Examples: `StringReverse`, `BooleanAnd`, `PathJoin`
|
|
285
|
-
- `To*` - Conversion operations
|
|
286
|
-
- Examples: `ToString`, `ToNumber`, `ToBoolean`
|
|
287
|
-
|
|
288
|
-
#### 4.3 Alias Types
|
|
289
|
-
|
|
290
|
-
Provide intuitive aliases when appropriate:
|
|
291
|
-
|
|
292
|
-
```typescript
|
|
293
|
-
export type BooleanAll<T extends readonly boolean[]> = ...
|
|
294
|
-
export type BooleanEvery<T extends readonly boolean[]> = BooleanAll<T>
|
|
295
|
-
|
|
296
|
-
export type BooleanAny<T extends readonly boolean[]> = ...
|
|
297
|
-
export type BooleanSome<T extends readonly boolean[]> = BooleanAny<T>
|
|
298
|
-
```
|
|
299
|
-
|
|
300
|
-
### 5. Export Strategy
|
|
301
|
-
|
|
302
|
-
```typescript
|
|
303
|
-
// Always export public types
|
|
304
|
-
export type PublicType<T> = ...
|
|
305
|
-
|
|
306
|
-
// Never export internal helpers
|
|
307
|
-
type InternalHelper<T, Acc> = ...
|
|
308
|
-
|
|
309
|
-
// Export commonly used aliases
|
|
310
|
-
export type Alias<T> = PublicType<T>
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### 6. Common Pitfalls to Avoid
|
|
314
|
-
|
|
315
|
-
1. ❌ **Don't expose implementation details** in public APIs
|
|
316
|
-
2. ❌ **Don't use ambiguous names** (prefer `StringLength` over `Length`)
|
|
317
|
-
3. ❌ **Don't skip documentation** - every export needs JSDoc comments
|
|
318
|
-
4. ❌ **Don't forget edge cases** in examples
|
|
319
|
-
5. ❌ **Don't create circular dependencies** between types
|
|
320
|
-
6. ❌ **Don't over-optimize** at the cost of readability
|
|
321
|
-
7. ❌ **Don't use overly generic names** that might cause conflicts
|
|
322
|
-
|
|
323
|
-
## Thanks
|
|
324
|
-
|
|
325
|
-
This module is inspired by and borrows ideas from the following projects:
|
|
326
|
-
|
|
327
|
-
- [ts-toolbelt](https://github.com/millsp/ts-toolbelt): 👷 TypeScript's largest type utility library.
|
|
328
|
-
- [type-fest](https://github.com/sindresorhus/type-fest): A collection of essential TypeScript types.
|
|
329
|
-
- [ts-essentials](https://github.com/ts-essentials/ts-essentials): All essential TypeScript types in one place 🤙
|
|
330
|
-
- [type-challenges](https://github.com/type-challenges/type-challenges): Collection of TypeScript type challenges with online judge.
|
|
71
|
+
- 若程序元素是函数,则只为该函数编写一个测试,如果该函数需要测试多个用例,应放在同一个测试中。
|
|
72
|
+
- 若程序元素是类,则至少要为该类的每一个方法编写一个测试,如果该方法需要测试多个用例,应放在同一个测试中。
|
|
73
|
+
- 若程序元素是类,除了为该类的每一个方法编写至少一个测试之外,还可以为该类编写任意多个测试,以覆盖该类的不同使用场景或边界情况。
|
|
74
|
+
- 若编写测试时需要用到辅助元素(Mock 或 Spy 等),可以在测试文件中直接定义这些辅助元素。若辅助元素较为简单,则可以直接放在每一个测试内部,优先保证每个测试的独立性,而不是追求极致 DRY;若辅助元素较为复杂或需要在多个测试中复用,则可以放在测试文件顶部,供该测试文件中的所有测试使用。
|
|
75
|
+
- 测试顺序应与源文件中被测试目标的原始顺序保持一致。
|
|
76
|
+
- 此模块暂时不需要任何测试,类型系统的测试通常需要特定的工具链支持,开发和维护成本较高,因此在没有明确需求的情况下,先保持模块的纯粹封装性质也是合理的。
|
|
77
|
+
- 模块的单元测试文件目录是 `./tests/unit/type`,若模块包含子模块,则子模块的单元测试文件目录为 `./tests/unit/type/<sub-module-name>`。
|
package/src/type/class.ts
CHANGED
|
@@ -15,7 +15,7 @@
|
|
|
15
15
|
* type Example2 = ClassConstructor<Date>
|
|
16
16
|
* ```
|
|
17
17
|
*/
|
|
18
|
-
export type ClassConstructor<Instance = unknown, Args extends
|
|
18
|
+
export type ClassConstructor<Instance = unknown, Args extends any[] = any[]> =
|
|
19
19
|
new (...args: Args) => Instance
|
|
20
20
|
|
|
21
21
|
/**
|
|
@@ -28,7 +28,7 @@ export type ClassConstructor<Instance = unknown, Args extends readonly unknown[]
|
|
|
28
28
|
* type Example1 = ClassAbstractConstructor<Base>
|
|
29
29
|
* ```
|
|
30
30
|
*/
|
|
31
|
-
export type ClassAbstractConstructor<Instance = unknown, Args extends
|
|
31
|
+
export type ClassAbstractConstructor<Instance = unknown, Args extends any[] = any[]> =
|
|
32
32
|
abstract new (...args: Args) => Instance
|
|
33
33
|
|
|
34
34
|
/**
|
package/src/type/index.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
|
-
export * from "./helper.ts"
|
|
2
|
-
export * from "./is.ts"
|
|
3
|
-
export * from "./union.ts"
|
|
4
|
-
export * from "./intersection.ts"
|
|
5
|
-
export * from "./string.ts"
|
|
6
|
-
export * from "./path.ts"
|
|
7
|
-
export * from "./boolean.ts"
|
|
8
|
-
export * from "./number.ts"
|
|
9
|
-
export * from "./object.ts"
|
|
10
|
-
export * from "./function.ts"
|
|
11
|
-
export * from "./tuple.ts"
|
|
12
|
-
export * from "./array.ts"
|
|
13
|
-
export * from "./class.ts"
|
|
14
|
-
export * from "./iteration.ts"
|
|
1
|
+
export type * from "./helper.ts"
|
|
2
|
+
export type * from "./is.ts"
|
|
3
|
+
export type * from "./union.ts"
|
|
4
|
+
export type * from "./intersection.ts"
|
|
5
|
+
export type * from "./string.ts"
|
|
6
|
+
export type * from "./path.ts"
|
|
7
|
+
export type * from "./boolean.ts"
|
|
8
|
+
export type * from "./number.ts"
|
|
9
|
+
export type * from "./object.ts"
|
|
10
|
+
export type * from "./function.ts"
|
|
11
|
+
export type * from "./tuple.ts"
|
|
12
|
+
export type * from "./array.ts"
|
|
13
|
+
export type * from "./class.ts"
|
|
14
|
+
export type * from "./iteration.ts"
|