schema-dsl 1.2.5 → 2.0.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 (243) hide show
  1. package/CHANGELOG.md +130 -238
  2. package/LICENSE +21 -21
  3. package/README.md +628 -2486
  4. package/dist/DslBuilder-BIgQOAXp.d.ts +343 -0
  5. package/dist/DslBuilder-CjHTucNQ.d.cts +343 -0
  6. package/dist/Validator-CllRdrY0.d.ts +192 -0
  7. package/dist/Validator-D6okG9tr.d.cts +192 -0
  8. package/dist/index.cjs +6640 -0
  9. package/dist/index.d.cts +1151 -0
  10. package/dist/index.d.ts +1151 -0
  11. package/dist/index.js +6574 -0
  12. package/dist/plugin-CIKtTMtS.d.cts +246 -0
  13. package/dist/plugin-CIKtTMtS.d.ts +246 -0
  14. package/dist/plugins/custom-format.cjs +3818 -0
  15. package/dist/plugins/custom-format.d.cts +12 -0
  16. package/dist/plugins/custom-format.d.ts +12 -0
  17. package/dist/plugins/custom-format.js +3788 -0
  18. package/dist/plugins/custom-type-example.cjs +3811 -0
  19. package/dist/plugins/custom-type-example.d.cts +8 -0
  20. package/dist/plugins/custom-type-example.d.ts +8 -0
  21. package/dist/plugins/custom-type-example.js +3781 -0
  22. package/dist/plugins/custom-validator.cjs +144 -0
  23. package/dist/plugins/custom-validator.d.cts +10 -0
  24. package/dist/plugins/custom-validator.d.ts +10 -0
  25. package/dist/plugins/custom-validator.js +119 -0
  26. package/docs/FEATURE-INDEX.md +553 -519
  27. package/docs/add-custom-locale.md +496 -483
  28. package/docs/add-keyword.md +24 -0
  29. package/docs/api-reference.md +1047 -805
  30. package/docs/api.md +13 -0
  31. package/docs/best-practices-project-structure.md +417 -408
  32. package/docs/best-practices.md +712 -672
  33. package/docs/cache-manager.md +344 -336
  34. package/docs/compile.md +45 -0
  35. package/docs/conditional-api.md +1307 -1278
  36. package/docs/custom-extensions-guide.md +339 -411
  37. package/docs/design-philosophy.md +606 -601
  38. package/docs/doc-index.md +324 -0
  39. package/docs/dsl-syntax.md +714 -664
  40. package/docs/dynamic-locale.md +608 -598
  41. package/docs/enum.md +482 -475
  42. package/docs/error-handling.md +1975 -1966
  43. package/docs/export-guide.md +501 -462
  44. package/docs/export-limitations.md +567 -551
  45. package/docs/faq.md +596 -577
  46. package/docs/frontend-i18n-guide.md +307 -293
  47. package/docs/i18n-user-guide.md +487 -474
  48. package/docs/i18n.md +476 -457
  49. package/docs/index.md +48 -0
  50. package/docs/json-schema-basics.md +40 -0
  51. package/docs/label-vs-description.md +271 -262
  52. package/docs/markdown-exporter.md +406 -397
  53. package/docs/mongodb-exporter.md +302 -295
  54. package/docs/multi-language.md +26 -0
  55. package/docs/multi-type-support.md +322 -329
  56. package/docs/mysql-exporter.md +280 -273
  57. package/docs/number-operators.md +449 -442
  58. package/docs/optional-marker-guide.md +326 -321
  59. package/docs/performance-guide.md +49 -0
  60. package/docs/plugin-system.md +381 -542
  61. package/docs/plugin-type-registration.md +34 -0
  62. package/docs/postgresql-exporter.md +311 -304
  63. package/docs/public/favicon.svg +5 -0
  64. package/docs/quick-start.md +435 -761
  65. package/docs/runtime-locale-support.md +532 -521
  66. package/docs/schema-helper.md +345 -340
  67. package/docs/schema-utils-advanced-issues.md +23 -0
  68. package/docs/schema-utils-best-practices.md +20 -0
  69. package/docs/schema-utils-chaining.md +150 -143
  70. package/docs/schema-utils.md +524 -490
  71. package/docs/security-checklist.md +20 -0
  72. package/docs/string-extensions.md +488 -480
  73. package/docs/troubleshooting.md +486 -471
  74. package/docs/type-converter.md +310 -319
  75. package/docs/type-reference.md +242 -219
  76. package/docs/typescript-guide.md +584 -573
  77. package/docs/union-type-guide.md +157 -147
  78. package/docs/union-types.md +284 -277
  79. package/docs/validate-async.md +491 -480
  80. package/docs/validate-batch.md +49 -0
  81. package/docs/validate-dsl-object-support.md +578 -573
  82. package/docs/validate.md +506 -486
  83. package/docs/validation-guide.md +502 -484
  84. package/docs/validator.md +39 -0
  85. package/package.json +131 -73
  86. package/plugins/custom-format.cjs +8 -0
  87. package/plugins/custom-type-example.cjs +8 -0
  88. package/plugins/custom-validator.cjs +8 -0
  89. package/src/adapters/DslAdapter.ts +111 -0
  90. package/src/adapters/index.ts +1 -0
  91. package/src/config/constants.ts +83 -0
  92. package/src/config/index.ts +2 -0
  93. package/src/config/patterns.ts +77 -0
  94. package/src/core/CacheManager.ts +169 -0
  95. package/src/core/ConditionalBuilder.ts +382 -0
  96. package/src/core/ConditionalRuntime.ts +28 -0
  97. package/src/core/ConditionalValidator.ts +255 -0
  98. package/src/core/DslBuilder.ts +687 -0
  99. package/src/core/ErrorCodes.ts +38 -0
  100. package/src/core/ErrorFormatter.ts +271 -0
  101. package/src/core/JSONSchemaCore.ts +65 -0
  102. package/src/core/Locale.ts +187 -0
  103. package/src/core/MessageTemplate.ts +42 -0
  104. package/src/core/ObjectDslBuilder.ts +64 -0
  105. package/src/core/PluginManager.ts +326 -0
  106. package/src/core/StringExtensions.ts +140 -0
  107. package/src/core/TemplateEngine.ts +44 -0
  108. package/src/core/Validator.ts +448 -0
  109. package/src/errors/I18nError.ts +159 -0
  110. package/src/errors/ValidationError.ts +105 -0
  111. package/src/exporters/BaseExporter.ts +60 -0
  112. package/src/exporters/MarkdownExporter.ts +305 -0
  113. package/src/exporters/MongoDBExporter.ts +126 -0
  114. package/src/exporters/MySQLExporter.ts +156 -0
  115. package/src/exporters/PostgreSQLExporter.ts +222 -0
  116. package/src/exporters/index.ts +18 -0
  117. package/src/index.ts +651 -0
  118. package/{lib/locales/en-US.js → src/locales/en-US.ts} +160 -176
  119. package/{lib/locales/es-ES.js → src/locales/es-ES.ts} +160 -113
  120. package/{lib/locales/fr-FR.js → src/locales/fr-FR.ts} +160 -113
  121. package/src/locales/index.ts +103 -0
  122. package/{lib/locales/ja-JP.js → src/locales/ja-JP.ts} +160 -118
  123. package/src/locales/types.ts +156 -0
  124. package/{lib/locales/zh-CN.js → src/locales/zh-CN.ts} +160 -177
  125. package/src/parser/ConstraintParser.ts +101 -0
  126. package/src/parser/DslParser.ts +470 -0
  127. package/src/parser/SchemaCompiler.ts +66 -0
  128. package/src/parser/TypeRegistry.ts +250 -0
  129. package/src/parser/index.ts +6 -0
  130. package/src/plugins/custom-format.ts +124 -0
  131. package/src/plugins/custom-type-example.ts +106 -0
  132. package/src/plugins/custom-validator.ts +138 -0
  133. package/src/types/conditional.ts +28 -0
  134. package/src/types/config.ts +59 -0
  135. package/src/types/dsl.ts +131 -0
  136. package/src/types/error.ts +60 -0
  137. package/src/types/index.ts +17 -0
  138. package/src/types/infer.ts +128 -0
  139. package/src/types/plugin.ts +58 -0
  140. package/src/types/safe-regex.d.ts +9 -0
  141. package/src/types/schema.ts +66 -0
  142. package/src/types/validate.ts +71 -0
  143. package/src/utils/SchemaHelper.ts +196 -0
  144. package/src/utils/SchemaUtils.ts +365 -0
  145. package/src/utils/TypeConverter.ts +215 -0
  146. package/src/utils/index.ts +10 -0
  147. package/src/validators/CustomKeywords.ts +477 -0
  148. package/.eslintignore +0 -11
  149. package/.eslintrc.json +0 -27
  150. package/CONTRIBUTING.md +0 -368
  151. package/STATUS.md +0 -491
  152. package/changelogs/v1.0.0.md +0 -328
  153. package/changelogs/v1.0.9.md +0 -367
  154. package/changelogs/v1.1.0.md +0 -389
  155. package/changelogs/v1.1.1.md +0 -308
  156. package/changelogs/v1.1.2.md +0 -183
  157. package/changelogs/v1.1.3.md +0 -161
  158. package/changelogs/v1.1.4.md +0 -432
  159. package/changelogs/v1.1.5.md +0 -493
  160. package/changelogs/v1.1.6.md +0 -211
  161. package/changelogs/v1.1.8.md +0 -376
  162. package/changelogs/v1.2.3.md +0 -124
  163. package/docs/INDEX.md +0 -252
  164. package/docs/issues-resolved-summary.md +0 -196
  165. package/docs/performance-benchmark-report.md +0 -179
  166. package/docs/performance-quick-reference.md +0 -123
  167. package/docs/user-questions-answered.md +0 -353
  168. package/docs/validation-rules-v1.0.2.md +0 -1608
  169. package/examples/README.md +0 -81
  170. package/examples/array-dsl-example.js +0 -227
  171. package/examples/conditional-example.js +0 -288
  172. package/examples/conditional-non-object.js +0 -129
  173. package/examples/conditional-validate-example.js +0 -321
  174. package/examples/custom-extension.js +0 -85
  175. package/examples/dsl-match-example.js +0 -74
  176. package/examples/dsl-style.js +0 -118
  177. package/examples/dynamic-locale-configuration.js +0 -348
  178. package/examples/dynamic-locale-example.js +0 -287
  179. package/examples/enum.examples.js +0 -324
  180. package/examples/export-demo.js +0 -130
  181. package/examples/express-integration.js +0 -376
  182. package/examples/i18n-error-handling-complete.js +0 -381
  183. package/examples/i18n-error-handling-quickstart.md +0 -0
  184. package/examples/i18n-error.examples.js +0 -181
  185. package/examples/i18n-full-demo.js +0 -301
  186. package/examples/i18n-memory-safety.examples.js +0 -268
  187. package/examples/markdown-export.js +0 -71
  188. package/examples/middleware-usage.js +0 -93
  189. package/examples/new-features-comparison.js +0 -315
  190. package/examples/password-reset/README.md +0 -153
  191. package/examples/password-reset/schema.js +0 -26
  192. package/examples/password-reset/test.js +0 -101
  193. package/examples/plugin-system.examples.js +0 -205
  194. package/examples/schema-utils-chaining.examples.js +0 -250
  195. package/examples/simple-example.js +0 -122
  196. package/examples/slug.examples.js +0 -179
  197. package/examples/string-extensions.js +0 -297
  198. package/examples/union-type-example.js +0 -127
  199. package/examples/union-types-example.js +0 -77
  200. package/examples/user-registration/README.md +0 -156
  201. package/examples/user-registration/routes.js +0 -92
  202. package/examples/user-registration/schema.js +0 -150
  203. package/examples/user-registration/server.js +0 -74
  204. package/index.d.ts +0 -3658
  205. package/index.js +0 -475
  206. package/index.mjs +0 -60
  207. package/lib/adapters/DslAdapter.js +0 -995
  208. package/lib/adapters/index.js +0 -20
  209. package/lib/config/constants.js +0 -286
  210. package/lib/config/patterns/common.js +0 -47
  211. package/lib/config/patterns/creditCard.js +0 -9
  212. package/lib/config/patterns/idCard.js +0 -9
  213. package/lib/config/patterns/index.js +0 -9
  214. package/lib/config/patterns/licensePlate.js +0 -4
  215. package/lib/config/patterns/passport.js +0 -4
  216. package/lib/config/patterns/phone.js +0 -9
  217. package/lib/config/patterns/postalCode.js +0 -5
  218. package/lib/core/CacheManager.js +0 -376
  219. package/lib/core/ConditionalBuilder.js +0 -503
  220. package/lib/core/DslBuilder.js +0 -1589
  221. package/lib/core/ErrorCodes.js +0 -233
  222. package/lib/core/ErrorFormatter.js +0 -445
  223. package/lib/core/JSONSchemaCore.js +0 -347
  224. package/lib/core/Locale.js +0 -130
  225. package/lib/core/MessageTemplate.js +0 -98
  226. package/lib/core/PluginManager.js +0 -448
  227. package/lib/core/StringExtensions.js +0 -240
  228. package/lib/core/Validator.js +0 -654
  229. package/lib/errors/I18nError.js +0 -328
  230. package/lib/errors/ValidationError.js +0 -191
  231. package/lib/exporters/MarkdownExporter.js +0 -420
  232. package/lib/exporters/MongoDBExporter.js +0 -162
  233. package/lib/exporters/MySQLExporter.js +0 -212
  234. package/lib/exporters/PostgreSQLExporter.js +0 -289
  235. package/lib/exporters/index.js +0 -24
  236. package/lib/locales/index.js +0 -8
  237. package/lib/utils/LRUCache.js +0 -174
  238. package/lib/utils/SchemaHelper.js +0 -240
  239. package/lib/utils/SchemaUtils.js +0 -445
  240. package/lib/utils/TypeConverter.js +0 -245
  241. package/lib/utils/index.js +0 -13
  242. package/lib/validators/CustomKeywords.js +0 -616
  243. package/lib/validators/index.js +0 -11
@@ -1,573 +1,584 @@
1
- # TypeScript 使用指南
2
-
3
- > **版本**: schema-dsl v1.0.6+
4
- > **更新日期**: 2026-01-04
5
- > **重要**: v1.0.6 移除了全局 String 类型扩展以避免类型污染
6
-
7
- ---
8
-
9
- ## 📋 目录
10
-
11
- 1. [快速开始](#1-快速开始)
12
- 2. [TypeScript 中的链式调用](#2-typescript-中的链式调用)
13
- 3. [类型推导最佳实践](#3-类型推导最佳实践)
14
- 4. [完整示例](#4-完整示例)
15
- 5. [常见问题](#5-常见问题)
16
-
17
- ---
18
-
19
- ## 1. 快速开始
20
-
21
- ### 1.1 安装
22
-
23
- ```bash
24
- npm install schema-dsl
25
- ```
26
-
27
- ### 1.2 基础用法
28
-
29
- ```typescript
30
- import { dsl, validate } from 'schema-dsl';
31
-
32
- // 定义 Schema
33
- const userSchema = dsl({
34
- username: 'string:3-32!',
35
- email: 'email!',
36
- age: 'number:18-100'
37
- });
38
-
39
- // 验证数据
40
- const result = validate(userSchema, {
41
- username: 'testuser',
42
- email: 'test@example.com',
43
- age: 25
44
- });
45
-
46
- if (result.valid) {
47
- console.log('验证通过:', result.data);
48
- } else {
49
- console.log('验证失败:', result.errors);
50
- }
51
- ```
52
-
53
- ---
54
-
55
- ## 2. TypeScript 中的链式调用
56
-
57
- ### 2.1 重要变更(v1.0.6)
58
-
59
- **v1.0.6 移除了全局 `interface String` 扩展**,原因:
60
- - ❌ 全局类型扩展会污染原生 String 类型
61
- - ❌ 导致 `trim()`、`toLowerCase()` 等原生方法的类型推断错误
62
- - ❌ 影响所有使用 TypeScript 的项目的类型安全
63
-
64
- **结果**:在 TypeScript 中直接对字符串链式调用会报类型错误:
65
-
66
- ```typescript
67
- // ❌ TypeScript 中会报错(v1.0.6+)
68
- const schema = dsl({
69
- email: 'email!'.label('邮箱') // 类型错误:Property 'label' does not exist on type 'string'
70
- });
71
-
72
- // ✅ JavaScript 中仍然可以正常使用
73
- const schema = dsl({
74
- email: 'email!'.label('邮箱') // 运行时完全正常
75
- });
76
- ```
77
-
78
- ### 2.2 正确用法 ⭐⭐⭐
79
-
80
- **TypeScript 中必须使用 `dsl()` 函数包裹字符串**,才能获得类型提示和链式调用:
81
-
82
- ```typescript
83
- // ✅ 正确:使用 dsl() 包裹(v1.0.6+ 必须)
84
- const schema = dsl({
85
- email: dsl('email!').label('邮箱').pattern(/custom/)
86
- });
87
-
88
- // ✅ 也可以先定义再使用
89
- const emailField = dsl('email!').label('邮箱');
90
- const schema = dsl({ email: emailField });
91
- ```
92
-
93
- **好处**:
94
- - ✅ 获得完整的类型推导和 IDE 自动提示
95
- - ✅ 不污染原生 String 类型(`trim()` 正确返回 `string`)
96
- - ✅ 更好的类型安全和开发体验
97
-
98
- ### 2.3 工作原理
99
-
100
- ```typescript
101
- // dsl(string) 返回 DslBuilder 实例
102
- const emailBuilder = dsl('email!');
103
- // ^? DslBuilder - 完整的类型定义
104
-
105
- // DslBuilder 支持所有链式方法,并有完整类型提示
106
- emailBuilder.label('邮箱')
107
- // ^? IDE 自动提示所有可用方法
108
- .pattern(/^[a-z]+@[a-z]+\.[a-z]+$/)
109
- .messages({ required: '邮箱必填' });
110
- ```
111
-
112
- ---
113
-
114
- ## 3. 类型推导最佳实践
115
-
116
- ### 3.1 方式对比
117
-
118
- | 方式 | JavaScript | TypeScript | 类型推导 | 推荐度 |
119
- |------|-----------|-----------|---------|--------|
120
- | 直接字符串 | ✅ 完美 | ⚠️ 可能无提示 | ❌ 弱 | ⭐⭐ |
121
- | dsl() 包裹 | 完美 | 完美 | | ⭐⭐⭐⭐⭐ |
122
- | 先定义再使用 | ✅ 完美 | ✅ 完美 | ✅ 强 | ⭐⭐⭐⭐ |
123
-
124
- ### 3.2 推荐写法
125
-
126
- #### ✅ 方式 1: 内联使用 dsl() 包裹(最推荐)
127
-
128
- ```typescript
129
- const schema = dsl({
130
- username: dsl('string:3-32!')
131
- .pattern(/^[a-zA-Z0-9_]+$/, '只能包含字母、数字和下划线')
132
- .label('用户名'),
133
-
134
- email: dsl('email!')
135
- .label('邮箱地址')
136
- .messages({ required: '邮箱必填' }),
137
-
138
- age: dsl('number:18-100')
139
- .label('年龄')
140
- });
141
- ```
142
-
143
- **优点**:
144
- - ✅ 完整的类型推导
145
- - ✅ IDE 自动提示所有方法
146
- - ✅ 代码紧凑,逻辑清晰
147
-
148
- ####方式 2: 先定义字段,再组合(适合复用)
149
-
150
- ```typescript
151
- // 定义可复用的字段
152
- const emailField = dsl('email!')
153
- .label('邮箱地址')
154
- .messages({ required: '邮箱必填' });
155
-
156
- const usernameField = dsl('string:3-32!')
157
- .pattern(/^[a-zA-Z0-9_]+$/)
158
- .label('用户名');
159
-
160
- // 组合使用
161
- const registrationSchema = dsl({
162
- email: emailField,
163
- username: usernameField,
164
- password: dsl('string:8-64!').password('strong')
165
- });
166
-
167
- const loginSchema = dsl({
168
- email: emailField, // 复用
169
- password: dsl('string!').label('密码')
170
- });
171
- ```
172
-
173
- **优点**:
174
- - ✅ 字段定义可复用
175
- - 代码更模块化
176
- - 适合大型项目
177
-
178
- #### ❌ 不推荐的写法
179
-
180
- ```typescript
181
- // ❌ 在 TypeScript 中直接使用字符串链式调用
182
- const schema = dsl({
183
- email: 'email!'.label('邮箱') // 可能无类型提示
184
- });
185
-
186
- //混合使用(不一致)
187
- const schema = dsl({
188
- email: 'email!'.label('邮箱'), // 字符串扩展
189
- username: dsl('string!').label('用户名') // dsl 包裹
190
- });
191
- ```
192
-
193
- ---
194
-
195
- ## 4. 完整示例
196
-
197
- ### 4.1 用户注册表单
198
-
199
- ```typescript
200
- import { dsl, validateAsync, ValidationError } from 'schema-dsl';
201
-
202
- // 定义 Schema
203
- const registrationSchema = dsl({
204
- profile: dsl({
205
- username: dsl('string:3-32!')
206
- .pattern(/^[a-zA-Z0-9_]+$/, '只能包含字母、数字和下划线')
207
- .label('用户名')
208
- .messages({
209
- min: '用户名至少3个字符',
210
- max: '用户名最多32个字符'
211
- }),
212
-
213
- email: dsl('email!')
214
- .label('邮箱地址')
215
- .messages({ required: '邮箱必填' }),
216
-
217
- password: dsl('string!')
218
- .password('strong')
219
- .label('密码'),
220
-
221
- age: dsl('number:18-100')
222
- .label('年龄')
223
- }),
224
-
225
- settings: dsl({
226
- emailNotify: dsl('boolean')
227
- .default(true)
228
- .label('邮件通知'),
229
-
230
- language: dsl('string')
231
- .default('zh-CN')
232
- .label('语言设置')
233
- })
234
- });
235
-
236
- // 异步验证(推荐)
237
- async function registerUser(data: any) {
238
- try {
239
- const validData = await validateAsync(registrationSchema, data);
240
- console.log('注册成功:', validData);
241
- return validData;
242
- } catch (error) {
243
- if (error instanceof ValidationError) {
244
- console.log('验证失败:');
245
- error.errors.forEach(err => {
246
- console.log(` - ${err.path}: ${err.message}`);
247
- });
248
- throw error;
249
- }
250
- throw error;
251
- }
252
- }
253
-
254
- // 使用
255
- registerUser({
256
- profile: {
257
- username: 'testuser',
258
- email: 'test@example.com',
259
- password: 'StrongPass123!',
260
- age: 25
261
- },
262
- settings: {
263
- emailNotify: true,
264
- language: 'en-US'
265
- }
266
- });
267
- ```
268
-
269
- ### 4.2 API 请求验证
270
-
271
- ```typescript
272
- import { dsl, validateAsync } from 'schema-dsl';
273
- import express from 'express';
274
-
275
- const app = express();
276
- app.use(express.json());
277
-
278
- // 定义 API Schema
279
- const createUserSchema = dsl({
280
- username: dsl('string:3-32!')
281
- .pattern(/^[a-zA-Z0-9_]+$/)
282
- .label('用户名'),
283
-
284
- email: dsl('email!').label('邮箱'),
285
-
286
- role: dsl('string')
287
- .default('user')
288
- .label('角色')
289
- });
290
-
291
- // 使用中间件
292
- app.post('/api/users', async (req, res) => {
293
- try {
294
- const validData = await validateAsync(createUserSchema, req.body);
295
-
296
- // 创建用户逻辑
297
- const user = await createUser(validData);
298
-
299
- res.json({ success: true, data: user });
300
- } catch (error) {
301
- if (error instanceof ValidationError) {
302
- res.status(400).json({
303
- success: false,
304
- errors: error.errors.map(e => ({
305
- field: e.path,
306
- message: e.message
307
- }))
308
- });
309
- } else {
310
- res.status(500).json({ success: false, message: '服务器错误' });
311
- }
312
- }
313
- });
314
- ```
315
-
316
- ### 4.3 表单字段复用
317
-
318
- ```typescript
319
- import { dsl } from 'schema-dsl';
320
-
321
- // 定义常用字段
322
- const commonFields = {
323
- email: dsl('email!')
324
- .label('邮箱地址')
325
- .messages({ required: '邮箱必填' }),
326
-
327
- username: dsl('string:3-32!')
328
- .pattern(/^[a-zA-Z0-9_]+$/)
329
- .label('用户名'),
330
-
331
- password: dsl('string!')
332
- .password('strong')
333
- .label('密码')
334
- };
335
-
336
- // 注册表单
337
- const registrationSchema = dsl({
338
- ...commonFields,
339
- confirmPassword: dsl('string!')
340
- .label('确认密码')
341
- });
342
-
343
- // 登录表单
344
- const loginSchema = dsl({
345
- email: commonFields.email,
346
- password: dsl('string!').label('密码') // 登录时不需要强密码验证
347
- });
348
-
349
- // 密码重置表单
350
- const resetPasswordSchema = dsl({
351
- email: commonFields.email,
352
- newPassword: commonFields.password,
353
- confirmPassword: dsl('string!').label('确认新密码')
354
- });
355
- ```
356
-
357
- ---
358
-
359
- ## 5. 常见问题
360
-
361
- ### 5.1 为什么 TypeScript 中字符串链式调用没有类型提示?
362
-
363
- **原因**: TypeScript 对全局 `String.prototype` 扩展的类型推导有限制。
364
-
365
- **解决**: 使用 `dsl()` 包裹字符串:
366
-
367
- ```typescript
368
- // ❌ 可能无提示
369
- 'email!'.label('邮箱')
370
-
371
- // 完整提示
372
- dsl('email!').label('邮箱')
373
- ```
374
-
375
- ### 5.2 JavaScript 用户需要改变写法吗?
376
-
377
- **不需要!** JavaScript 用户可以继续使用字符串链式调用:
378
-
379
- ```javascript
380
- // JavaScript 中完全正常
381
- const schema = dsl({
382
- email: 'email!'.label('邮箱')
383
- });
384
- ```
385
-
386
- ### 5.3 如何在严格模式下使用?
387
-
388
- `tsconfig.json` 中启用严格模式也没问题:
389
-
390
- ```json
391
- {
392
- "compilerOptions": {
393
- "strict": true,
394
- "noImplicitAny": true
395
- }
396
- }
397
- ```
398
-
399
- 只需使用 `dsl()` 包裹即可:
400
-
401
- ```typescript
402
- const schema = dsl({
403
- email: dsl('email!').label('邮箱') // ✅ 严格模式下正常
404
- });
405
- ```
406
-
407
- ### 5.4 如何获取验证后的数据类型?
408
-
409
- 使用泛型参数:
410
-
411
- ```typescript
412
- interface User {
413
- username: string;
414
- email: string;
415
- age?: number;
416
- }
417
-
418
- // 同步验证
419
- const result = validate<User>(userSchema, data);
420
- if (result.valid) {
421
- const user: User = result.data; // ✅ 类型安全
422
- }
423
-
424
- // 异步验证
425
- const validUser = await validateAsync<User>(userSchema, data);
426
- // ^? User - 完整的类型推导
427
- ```
428
-
429
- ### 5.5 如何处理嵌套对象的验证错误?
430
-
431
- ```typescript
432
- try {
433
- await validateAsync(schema, data);
434
- } catch (error) {
435
- if (error instanceof ValidationError) {
436
- // 方式 1: 遍历所有错误
437
- error.errors.forEach(err => {
438
- console.log(`${err.path}: ${err.message}`);
439
- // 输出: profile.username: 用户名至少3个字符
440
- });
441
-
442
- // 方式 2: 获取特定字段错误
443
- const usernameError = error.getFieldError('profile.username');
444
- if (usernameError) {
445
- console.log(usernameError.message);
446
- }
447
-
448
- // 方式 3: 获取所有字段错误映射
449
- const fieldErrors = error.getFieldErrors();
450
- // { 'profile.username': {...}, 'profile.email': {...} }
451
- }
452
- }
453
- ```
454
-
455
- ---
456
-
457
- ## 6. 进阶技巧
458
-
459
- ### 6.1 自定义验证器
460
-
461
- ```typescript
462
- const schema = dsl({
463
- username: dsl('string:3-32!')
464
- .custom(async (value) => {
465
- // 异步验证(检查用户名是否已存在)
466
- const exists = await checkUsernameExists(value);
467
- if (exists) {
468
- return { error: 'USERNAME_EXISTS', message: '用户名已存在' };
469
- }
470
- return true;
471
- })
472
- .label('用户名')
473
- });
474
- ```
475
-
476
- ### 6.2 条件验证
477
-
478
- ```typescript
479
- const schema = dsl({
480
- userType: dsl('string!').label('用户类型'),
481
-
482
- // 使用 dsl.match() 根据 userType 字段动态验证
483
- companyName: dsl.match('userType', {
484
- 'company': 'string!', // 企业用户必填
485
- '_default': 'string' // 个人用户可选
486
- })
487
- });
488
- ```
489
-
490
- ### 6.3 Schema 复用和扩展
491
-
492
- ```typescript
493
- import { SchemaUtils } from 'schema-dsl';
494
-
495
- // 基础用户 Schema
496
- const baseUserSchema = dsl({
497
- username: dsl('string:3-32!').label('用户名'),
498
- email: dsl('email!').label('邮箱')
499
- });
500
-
501
- // 扩展为管理员 Schema
502
- const adminSchema = SchemaUtils.extend(baseUserSchema.toJsonSchema(), {
503
- role: dsl('string!').default('admin').label('角色'),
504
- permissions: dsl('array<string>').label('权限列表')
505
- });
506
-
507
- // 只选择部分字段
508
- const publicUserSchema = SchemaUtils.pick(
509
- baseUserSchema.toJsonSchema(),
510
- ['username']
511
- );
512
- ```
513
-
514
- ---
515
-
516
- ## 7. 性能优化
517
-
518
- ### 7.1 Schema 预编译
519
-
520
- ```typescript
521
- // 预编译 Schema(只编译一次)
522
- const schema = dsl({
523
- email: dsl('email!').label('邮箱')
524
- });
525
- schema.compile(); // 预编译
526
-
527
- // 多次验证(使用缓存的编译结果)
528
- await validateAsync(schema, data1);
529
- await validateAsync(schema, data2);
530
- await validateAsync(schema, data3);
531
- ```
532
-
533
- ### 7.2 缓存配置
534
-
535
- ```typescript
536
- import { dsl } from 'schema-dsl';
537
-
538
- // 配置缓存大小
539
- dsl.config({
540
- cache: {
541
- maxSize: 5000, // 缓存条目数
542
- ttl: 60000 // 过期时间(毫秒)
543
- }
544
- });
545
- ```
546
-
547
- ---
548
-
549
- ## 8. 最佳实践总结
550
-
551
- 1. ✅ **TypeScript 中始终使用 `dsl()` 包裹字符串**
552
- 2. ✅ **使用 `validateAsync` 进行异步验证**
553
- 3. ✅ **为验证结果添加泛型类型参数**
554
- 4. ✅ **复用常用字段定义**
555
- 5. ✅ **使用 `ValidationError` 类型守卫处理错误**
556
- 6. ✅ **为用户提供友好的错误消息**
557
- 7. ✅ **预编译常用的 Schema**
558
-
559
- ---
560
-
561
- ## 9. 相关资源
562
-
563
- - [API 参考文档](./api-reference.md)
564
- - [DSL 语法完整指南](./dsl-syntax.md)
565
- - [验证规则参考](./validation-guide.md)
566
- - [错误处理指南](./error-handling.md)
567
- - [GitHub 仓库](https://github.com/vextjs/schema-dsl)
568
-
569
- ---
570
-
571
- **更新日期**: 2025-12-31
572
- **文档版本**: v1.0.4
573
-
1
+ # TypeScript 使用指南
2
+
3
+ > **版本**: schema-dsl v2.0.0-beta.2
4
+ > **更新日期**: 2026-05-08
5
+ > **重要**: v1.0.6 移除了全局 String 类型扩展以避免类型污染
6
+
7
+ ---
8
+
9
+ ## 📋 目录
10
+
11
+ 1. [快速开始](#1-快速开始)
12
+ 2. [TypeScript 中的链式调用](#2-typescript-中的链式调用)
13
+ 3. [类型推导最佳实践](#3-类型推导最佳实践)
14
+ 4. [完整示例](#4-完整示例)
15
+ 5. [常见问题](#5-常见问题)
16
+
17
+ ---
18
+
19
+ ## 1. 快速开始
20
+
21
+ ### 1.1 安装
22
+
23
+ ```bash
24
+ npm install schema-dsl
25
+ ```
26
+
27
+ ### 1.2 基础用法
28
+
29
+ ```typescript
30
+ import { dsl, validate } from 'schema-dsl';
31
+
32
+ // 定义 Schema
33
+ const userSchema = dsl({
34
+ username: 'string:3-32!',
35
+ email: 'email!',
36
+ age: 'number:18-100'
37
+ });
38
+
39
+ // 验证数据
40
+ const result = validate(userSchema, {
41
+ username: 'testuser',
42
+ email: 'test@example.com',
43
+ age: 25
44
+ });
45
+
46
+ if (result.valid) {
47
+ console.log('验证通过:', result.data);
48
+ } else {
49
+ console.log('验证失败:', result.errors);
50
+ }
51
+ ```
52
+
53
+ ---
54
+
55
+ ## 2. TypeScript 中的链式调用
56
+
57
+ ### 2.1 重要变更(v1.0.6)
58
+
59
+ **v1.0.6 移除了全局 `interface String` 扩展**,原因:
60
+ - ❌ 全局类型扩展会污染原生 String 类型
61
+ - ❌ 导致 `trim()`、`toLowerCase()` 等原生方法的类型推断错误
62
+ - ❌ 影响所有使用 TypeScript 的项目的类型安全
63
+
64
+ **结果**:在 TypeScript 中直接对字符串链式调用会报类型错误:
65
+
66
+ ```typescript
67
+ // ❌ TypeScript 中会报错(v1.0.6+)
68
+ const schema = dsl({
69
+ email: 'email!'.label('邮箱') // 类型错误:Property 'label' does not exist on type 'string'
70
+ });
71
+
72
+ // ✅ JavaScript 中仍然可以正常使用
73
+ const schema = dsl({
74
+ email: 'email!'.label('邮箱') // 运行时完全正常
75
+ });
76
+ ```
77
+
78
+ ### 2.2 正确用法 ⭐⭐⭐
79
+
80
+ **TypeScript 中必须使用 `dsl()` 函数包裹字符串**,才能获得类型提示和链式调用:
81
+
82
+ ```typescript
83
+ // ✅ 正确:使用 dsl() 包裹(v1.0.6+ 必须)
84
+ const schema = dsl({
85
+ email: dsl('email!').label('邮箱').pattern(/custom/)
86
+ });
87
+
88
+ // ✅ 也可以先定义再使用
89
+ const emailField = dsl('email!').label('邮箱');
90
+ const schema = dsl({ email: emailField });
91
+ ```
92
+
93
+ **好处**:
94
+ - ✅ 获得完整的类型推导和 IDE 自动提示
95
+ - ✅ 不污染原生 String 类型(`trim()` 正确返回 `string`)
96
+ - ✅ 更好的类型安全和开发体验
97
+
98
+ ### 2.3 工作原理
99
+
100
+ ```typescript
101
+ // dsl(string) 返回 DslBuilder 实例
102
+ const emailBuilder = dsl('email!');
103
+ // ^? DslBuilder - 完整的类型定义
104
+
105
+ // DslBuilder 支持所有链式方法,并有完整类型提示
106
+ emailBuilder.label('邮箱')
107
+ // ^? IDE 自动提示所有可用方法
108
+ .pattern(/^[a-z]+@[a-z]+\.[a-z]+$/)
109
+ .error({ required: '邮箱必填' });
110
+
111
+ > ℹ️ 当前类型声明优先覆盖稳定链式 API,例如 `label()`、`pattern()`、`error()`、`default()`。
112
+ > 某些运行时扩展方法依然可用,但如果类型声明未暴露,建议在 TypeScript 代码里优先改写为上述稳定组合。
113
+ ```
114
+
115
+ ---
116
+
117
+ ## 3. 类型推导最佳实践
118
+
119
+ ### 3.1 方式对比
120
+
121
+ | 方式 | JavaScript | TypeScript | 类型推导 | 推荐度 |
122
+ |------|-----------|-----------|---------|--------|
123
+ | 直接字符串 | ✅ 完美 | ⚠️ 可能无提示 | ❌ 弱 | ⭐⭐ |
124
+ | dsl() 包裹 | ✅ 完美 | ✅ 完美 | ✅ 强 | ⭐⭐⭐⭐⭐ |
125
+ | 先定义再使用 | ✅ 完美 | ✅ 完美 | ✅ 强 | ⭐⭐⭐⭐ |
126
+
127
+ ### 3.2 推荐写法
128
+
129
+ #### 方式 1: 内联使用 dsl() 包裹(最推荐)
130
+
131
+ ```typescript
132
+ const schema = dsl({
133
+ username: dsl('string:3-32!')
134
+ .pattern(/^[a-zA-Z0-9_]+$/)
135
+ .label('用户名'),
136
+ .error({ pattern: '只能包含字母、数字和下划线' }),
137
+
138
+ email: dsl('email!')
139
+ .label('邮箱地址')
140
+ .error({ required: '邮箱必填' }),
141
+
142
+ age: dsl('number:18-100')
143
+ .label('年龄')
144
+ });
145
+ ```
146
+
147
+ **优点**:
148
+ -完整的类型推导
149
+ - ✅ IDE 自动提示所有方法
150
+ - ✅ 代码紧凑,逻辑清晰
151
+
152
+ #### 方式 2: 先定义字段,再组合(适合复用)
153
+
154
+ ```typescript
155
+ // 定义可复用的字段
156
+ const emailField = dsl('email!')
157
+ .label('邮箱地址')
158
+ .error({ required: '邮箱必填' });
159
+
160
+ const usernameField = dsl('string:3-32!')
161
+ .pattern(/^[a-zA-Z0-9_]+$/)
162
+ .label('用户名')
163
+ .error({ pattern: '用户名只能包含字母、数字和下划线' });
164
+
165
+ // 组合使用
166
+ const registrationSchema = dsl({
167
+ email: emailField,
168
+ username: usernameField,
169
+ password: dsl('string:8-64!')
170
+ .pattern(/^(?=.*[A-Za-z])(?=.*\d).{8,}$/)
171
+ .label('密码')
172
+ .error({ pattern: '密码至少 8 位且必须包含字母和数字' })
173
+ });
174
+
175
+ const loginSchema = dsl({
176
+ email: emailField, // 复用
177
+ password: dsl('string!').label('密码')
178
+ });
179
+ ```
180
+
181
+ **优点**:
182
+ - 字段定义可复用
183
+ - 代码更模块化
184
+ - ✅ 适合大型项目
185
+
186
+ ####不推荐的写法
187
+
188
+ ```typescript
189
+ // 在 TypeScript 中直接使用字符串链式调用
190
+ const schema = dsl({
191
+ email: 'email!'.label('邮箱') // 可能无类型提示
192
+ });
193
+
194
+ // ❌ 混合使用(不一致)
195
+ const schema = dsl({
196
+ email: 'email!'.label('邮箱'), // 字符串扩展
197
+ username: dsl('string!').label('用户名') // dsl 包裹
198
+ });
199
+ ```
200
+
201
+ ---
202
+
203
+ ## 4. 完整示例
204
+
205
+ ### 4.1 用户注册表单
206
+
207
+ ```typescript
208
+ import { dsl, validateAsync, ValidationError } from 'schema-dsl';
209
+
210
+ // 定义 Schema
211
+ const registrationSchema = dsl({
212
+ profile: dsl({
213
+ username: dsl('string:3-32!')
214
+ .pattern(/^[a-zA-Z0-9_]+$/)
215
+ .label('用户名')
216
+ .error({ pattern: '只能包含字母、数字和下划线' }),
217
+
218
+ email: dsl('email!')
219
+ .label('邮箱地址')
220
+ .error({ required: '邮箱必填' }),
221
+
222
+ password: dsl('string:8-64!')
223
+ .pattern(/^(?=.*[A-Za-z])(?=.*\d).{8,}$/)
224
+ .label('密码')
225
+ .error({ pattern: '密码至少 8 位且必须包含字母和数字' }),
226
+
227
+ age: dsl('number:18-100')
228
+ .label('年龄')
229
+ }),
230
+
231
+ settings: dsl({
232
+ emailNotify: dsl('boolean')
233
+ .default(true)
234
+ .label('邮件通知'),
235
+
236
+ language: dsl('string')
237
+ .default('zh-CN')
238
+ .label('语言设置')
239
+ })
240
+ });
241
+
242
+ // 异步验证(推荐)
243
+ async function registerUser(data: any) {
244
+ try {
245
+ const validData = await validateAsync(registrationSchema, data);
246
+ console.log('注册成功:', validData);
247
+ return validData;
248
+ } catch (error) {
249
+ if (error instanceof ValidationError) {
250
+ console.log('验证失败:');
251
+ error.errors.forEach(err => {
252
+ console.log(` - ${err.path}: ${err.message}`);
253
+ });
254
+ throw error;
255
+ }
256
+ throw error;
257
+ }
258
+ }
259
+
260
+ // 使用
261
+ registerUser({
262
+ profile: {
263
+ username: 'testuser',
264
+ email: 'test@example.com',
265
+ password: 'StrongPass123!',
266
+ age: 25
267
+ },
268
+ settings: {
269
+ emailNotify: true,
270
+ language: 'en-US'
271
+ }
272
+ });
273
+ ```
274
+
275
+ ### 4.2 API 请求验证
276
+
277
+ ```typescript
278
+ import { ValidationError, dsl, validateAsync } from 'schema-dsl';
279
+ import express from 'express';
280
+
281
+ const app = express();
282
+ app.use(express.json());
283
+
284
+ // 定义 API Schema
285
+ const createUserSchema = dsl({
286
+ username: dsl('string:3-32!')
287
+ .pattern(/^[a-zA-Z0-9_]+$/)
288
+ .label('用户名'),
289
+
290
+ email: dsl('email!').label('邮箱'),
291
+
292
+ role: dsl('string')
293
+ .default('user')
294
+ .label('角色')
295
+ });
296
+
297
+ // 使用中间件
298
+ app.post('/api/users', async (req, res) => {
299
+ try {
300
+ const validData = await validateAsync(createUserSchema, req.body);
301
+
302
+ // 创建用户逻辑
303
+ const user = await createUser(validData);
304
+
305
+ res.json({ success: true, data: user });
306
+ } catch (error) {
307
+ if (error instanceof ValidationError) {
308
+ res.status(400).json({
309
+ success: false,
310
+ errors: error.errors.map(e => ({
311
+ field: e.path,
312
+ message: e.message
313
+ }))
314
+ });
315
+ } else {
316
+ res.status(500).json({ success: false, message: '服务器错误' });
317
+ }
318
+ }
319
+ });
320
+ ```
321
+
322
+ ### 4.3 表单字段复用
323
+
324
+ ```typescript
325
+ import { dsl } from 'schema-dsl';
326
+
327
+ // 定义常用字段
328
+ const commonFields = {
329
+ email: dsl('email!')
330
+ .label('邮箱地址')
331
+ .error({ required: '邮箱必填' }),
332
+
333
+ username: dsl('string:3-32!')
334
+ .pattern(/^[a-zA-Z0-9_]+$/)
335
+ .label('用户名')
336
+ .error({ pattern: '用户名只能包含字母、数字和下划线' }),
337
+
338
+ password: dsl('string:8-64!')
339
+ .pattern(/^(?=.*[A-Za-z])(?=.*\d).{8,}$/)
340
+ .label('密码')
341
+ .error({ pattern: '密码至少 8 位且必须包含字母和数字' })
342
+ };
343
+
344
+ // 注册表单
345
+ const registrationSchema = dsl({
346
+ ...commonFields,
347
+ confirmPassword: dsl('string!')
348
+ .label('确认密码')
349
+ });
350
+
351
+ // 登录表单
352
+ const loginSchema = dsl({
353
+ email: commonFields.email,
354
+ password: dsl('string!').label('密码') // 登录时不需要强密码验证
355
+ });
356
+
357
+ // 密码重置表单
358
+ const resetPasswordSchema = dsl({
359
+ email: commonFields.email,
360
+ newPassword: commonFields.password,
361
+ confirmPassword: dsl('string!').label('确认新密码')
362
+ });
363
+ ```
364
+
365
+ ---
366
+
367
+ ## 5. 常见问题
368
+
369
+ ### 5.1 为什么 TypeScript 中字符串链式调用没有类型提示?
370
+
371
+ **原因**: TypeScript 对全局 `String.prototype` 扩展的类型推导有限制。
372
+
373
+ **解决**: 使用 `dsl()` 包裹字符串:
374
+
375
+ ```typescript
376
+ // ❌ 可能无提示
377
+ 'email!'.label('邮箱')
378
+
379
+ // ✅ 完整提示
380
+ dsl('email!').label('邮箱')
381
+ ```
382
+
383
+ ### 5.2 JavaScript 用户需要改变写法吗?
384
+
385
+ **不需要!** JavaScript 用户可以继续使用字符串链式调用:
386
+
387
+ ```javascript
388
+ // JavaScript 中完全正常
389
+ const schema = dsl({
390
+ email: 'email!'.label('邮箱')
391
+ });
392
+ ```
393
+
394
+ ### 5.3 如何在严格模式下使用?
395
+
396
+ 在 `tsconfig.json` 中启用严格模式也没问题:
397
+
398
+ ```json
399
+ {
400
+ "compilerOptions": {
401
+ "strict": true,
402
+ "noImplicitAny": true
403
+ }
404
+ }
405
+ ```
406
+
407
+ 只需使用 `dsl()` 包裹即可:
408
+
409
+ ```typescript
410
+ const schema = dsl({
411
+ email: dsl('email!').label('邮箱') // ✅ 严格模式下正常
412
+ });
413
+ ```
414
+
415
+ ### 5.4 如何获取验证后的数据类型?
416
+
417
+ 使用泛型参数:
418
+
419
+ ```typescript
420
+ interface User {
421
+ username: string;
422
+ email: string;
423
+ age?: number;
424
+ }
425
+
426
+ // 同步验证
427
+ const result = validate<User>(userSchema, data);
428
+ if (result.valid) {
429
+ const user: User = result.data; // ✅ 类型安全
430
+ }
431
+
432
+ // 异步验证
433
+ const validUser = await validateAsync<User>(userSchema, data);
434
+ // ^? User - 完整的类型推导
435
+ ```
436
+
437
+ ### 5.5 如何处理嵌套对象的验证错误?
438
+
439
+ ```typescript
440
+ try {
441
+ await validateAsync(schema, data);
442
+ } catch (error) {
443
+ if (error instanceof ValidationError) {
444
+ // 方式 1: 遍历所有错误
445
+ error.errors.forEach(err => {
446
+ console.log(`${err.path}: ${err.message}`);
447
+ // 输出: profile.username: 用户名至少3个字符
448
+ });
449
+
450
+ // 方式 2: 获取特定字段错误
451
+ const usernameError = error.getFieldError('profile.username');
452
+ if (usernameError) {
453
+ console.log(usernameError.message);
454
+ }
455
+
456
+ // 方式 3: 获取所有字段错误映射
457
+ const fieldErrors = error.getFieldErrors();
458
+ // { 'profile.username': {...}, 'profile.email': {...} }
459
+ }
460
+ }
461
+ ```
462
+
463
+ ---
464
+
465
+ ## 6. 进阶技巧
466
+
467
+ ### 6.1 额外业务规则
468
+
469
+ ```typescript
470
+ const schema = dsl({
471
+ username: dsl('string:3-32!').label('用户名')
472
+ });
473
+
474
+ const result = await validateAsync(schema, data);
475
+ if (result.username === 'admin') {
476
+ throw new Error('用户名已存在');
477
+ }
478
+ ```
479
+
480
+ 这种写法的好处是:结构校验仍由 schema-dsl 负责,业务唯一性、数据库查重等规则继续留在 TypeScript 业务层,避免把外部依赖塞进字段声明。
481
+
482
+ ### 6.2 条件验证
483
+
484
+ ```typescript
485
+ const schema = dsl({
486
+ userType: dsl('string!').label('用户类型'),
487
+
488
+ // 使用 dsl.match() 根据 userType 字段动态验证
489
+ companyName: dsl.match('userType', {
490
+ 'company': 'string!', // 企业用户必填
491
+ '_default': 'string' // 个人用户可选
492
+ })
493
+ });
494
+ ```
495
+
496
+ ### 6.3 Schema 复用和扩展
497
+
498
+ ```typescript
499
+ import { SchemaUtils } from 'schema-dsl';
500
+
501
+ // 基础用户 Schema
502
+ const baseUserSchema = dsl({
503
+ username: dsl('string:3-32!').label('用户名'),
504
+ email: dsl('email!').label('邮箱')
505
+ });
506
+
507
+ // 扩展为管理员 Schema
508
+ const adminSchema = SchemaUtils.extend(baseUserSchema, {
509
+ role: dsl('string!').default('admin').label('角色'),
510
+ permissions: dsl('array<string>').label('权限列表')
511
+ });
512
+
513
+ // 只选择部分字段
514
+ const publicUserSchema = SchemaUtils.pick(
515
+ baseUserSchema,
516
+ ['username']
517
+ );
518
+ ```
519
+
520
+ ---
521
+
522
+ ## 7. 性能优化
523
+
524
+ ### 7.1 复用 Schema 与默认缓存
525
+
526
+ ```typescript
527
+ const schema = dsl({
528
+ email: dsl('email!').label('邮箱')
529
+ });
530
+
531
+ // 多次验证会复用默认 Validator 的编译缓存
532
+ await validateAsync(schema, data1);
533
+ await validateAsync(schema, data2);
534
+ await validateAsync(schema, data3);
535
+ ```
536
+
537
+ ### 7.2 缓存配置
538
+
539
+ ```typescript
540
+ import { dsl } from 'schema-dsl';
541
+
542
+ // 配置缓存大小
543
+ dsl.config({
544
+ cache: {
545
+ maxSize: 5000, // 缓存条目数
546
+ ttl: 60000 // 过期时间(毫秒)
547
+ }
548
+ });
549
+ ```
550
+
551
+ ---
552
+
553
+ ## 8. 最佳实践总结
554
+
555
+ 1. ✅ **TypeScript 中始终使用 `dsl()` 包裹字符串**
556
+ 2. ✅ **使用 `validateAsync` 进行异步验证**
557
+ 3. ✅ **为验证结果添加泛型类型参数**
558
+ 4. ✅ **复用常用字段定义**
559
+ 5. ✅ **使用 `ValidationError` 类型守卫处理错误**
560
+ 6. ✅ **为用户提供友好的错误消息**
561
+ 7. ✅ **复用常用 Schema 对象,让默认缓存命中**
562
+
563
+ ---
564
+
565
+ ## 9. 相关资源
566
+
567
+ - [API 参考文档](./api-reference.md)
568
+ - [DSL 语法完整指南](./dsl-syntax.md)
569
+ - [验证规则参考](./validation-guide.md)
570
+ - [错误处理指南](./error-handling.md)
571
+ - [GitHub 仓库](https://github.com/vextjs/schema-dsl)
572
+
573
+ ---
574
+
575
+ ## 对应示例文件
576
+
577
+ **示例入口**: [typescript-guide.ts](https://github.com/vextjs/schema-dsl/blob/main/examples/docs/typescript-guide.ts)
578
+ **说明**: 展示 TypeScript 下推荐的 `dsl()` 包裹写法、`validate<T>()` / `validateAsync<T>()`、以及 `ValidationError` 的字段错误读取方式。
579
+
580
+ ---
581
+
582
+ **更新日期**: 2026-05-08
583
+ **文档版本**: v2.0.0-beta.2
584
+