String 扩展文档
更新时间: 2026-06-10
📑 目录
核心特性
导入 schema-dsl 后,字符串可以直接调用链式方法
const { dsl } = require('schema-dsl');
const schema = dsl({
// ✅ root entry 默认已安装 String 扩展
email: 'email!'.pattern(/custom/).label('邮箱'),
// ✅ 纯DSL仍然有效
age: 'number:18-120'
});
优势:
- ✅ 更简洁自然
- ✅ 减少代码量
- ✅ 与
dsl() 包裹写法可共存
替代方案(主动卸载后非侵入式)
如果你介意修改 String.prototype,可以主动卸载扩展,然后使用 dsl() 包裹字符串:
const { dsl, uninstallStringExtensions } = require('schema-dsl');
uninstallStringExtensions();
const schema = dsl({
// 使用 dsl() 包裹字符串
email: dsl('email!').pattern(/custom/).label('邮箱'),
// 纯DSL不受影响
age: 'number:18-120'
});
可用方法
下表示例默认在导入 schema-dsl 后即可使用。
快速开始
const { dsl } = require('schema-dsl');
const schema = dsl({
// 默认可以直接字符串链式调用
email: 'email!'.label('邮箱地址'),
username: 'string:3-32!'
.pattern(/^[a-zA-Z0-9_]+$/)
.label('用户名'),
// 简单字段用纯DSL
age: 'number:18-120',
role: 'user|admin'
});
详细示例
以下示例默认在导入 schema-dsl 后即可使用。如果你不想保留 String.prototype 扩展,可以先调用 uninstallStringExtensions(),再把每个复杂字段改写为 dsl('...') 包裹。
1. 正则验证
const schema = dsl({
username: 'string:3-32!'
.pattern(/^[a-zA-Z0-9_]+$/)
.messages({
'pattern': '只能包含字母、数字和下划线'
})
.label('用户名'),
phone: 'string:11!'
.pattern(/^1[3-9]\d{9}$/)
.messages({
'pattern': '请输入有效的手机号'
})
.label('手机号'),
password: 'string:8-64!'
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d).+$/)
.messages({
'pattern': '密码必须包含大小写字母和数字'
})
.label('密码')
});
正确的错误码:
'required' - 必填字段
'min' - 最小长度/值
'max' - 最大长度/值
'pattern' - 正则验证
'format' - 格式验证(email/url等)
'enum' - 枚举值
2. 自定义错误消息
const schema = dsl({
email: 'email!'
.label('邮箱地址')
.messages({
'format': '请输入有效的邮箱地址',
'required': '邮箱地址不能为空'
}),
bio: 'string:500'
.label('个人简介')
.messages({
'max': '个人简介不能超过{{#limit}}个字符'
}),
age: 'number:18-120'
.messages({
'min': '年龄不能小于{{#limit}}',
'max': '年龄不能大于{{#limit}}'
})
});
消息模板变量:
{{#label}} - 字段标签
{{#limit}} - 约束值(min/max)
{{#value}} - 当前值
{{#pattern}} - 正则表达式
3. 自定义验证器
const schema = dsl({
// 最优雅:只在失败时返回错误消息
username: 'string:3-32!'
.custom((value) => {
if (value === 'admin') return '用户名已被占用';
// 成功时无需返回
})
.label('用户名'),
// 支持同步验证
password: 'string:8-64!'
.custom((value) => {
if (!/[A-Z]/.test(value)) return '必须包含大写字母';
if (!/[a-z]/.test(value)) return '必须包含小写字母';
if (!/\d/.test(value)) return '必须包含数字';
})
.label('密码')
});
⚠️ .custom() 支持同步函数;需要异步查库或远程调用时,可以返回 Promise 并使用 validateAsync()。同步 validate() 遇到 Promise-returning custom validator 会返回明确错误。
支持的返回值:
- 不返回/
undefined → 验证通过 ✅
- 返回字符串 → 验证失败(错误消息)
- 返回
{ error, message } → 自定义错误码
- 抛出异常 → 验证失败
- 返回
true → 验证通过
- 返回
false → 验证失败(默认消息)
注意:
- 当前版本支持在
.custom() 中返回 Promise,但必须通过 validateAsync() 执行。
- 如果你希望把数据库/RPC/HTTP 检查留在业务层,也可以先用
schema-dsl 做结构校验,再在业务层执行异步检查。
5. 默认验证器
const schema = dsl({
// 用户名验证(自动正则+长度)
username: 'string!'.username('5-20'), // 5-20个字符
// 手机号验证
phone: 'string!'.phone('cn'), // 中国手机号
// 密码强度
password: 'string!'.password('strong'), // 强密码
// 身份证验证
idCard: 'string!'.idCard('cn'),
// URL别名验证
slug: 'string!'.slug()
});
username 预设:
'short' - 2-16
'medium' - 3-32(默认)
'long' - 5-64
'3-32' - 自定义范围
phone 支持的国家:
'cn' - 中国(11位)
'us' - 美国
'uk' - 英国
password 强度:
'weak' - 6-64
'medium' - 8-64(默认)
'strong' - 8-64(大小写+数字)
6. 完整表单示例
const { dsl, Validator } = require('schema-dsl');
const formSchema = dsl({
email: 'email!'
.label('邮箱地址')
.description('用于登录和接收通知')
.messages({
'format': '请输入有效的邮箱地址'
}),
username: 'string:3-32!'
.pattern(/^[a-zA-Z0-9_]+$/)
.messages({
'pattern': '只能包含字母、数字和下划线',
'min': '用户名至少3个字符',
'max': '用户名最多32个字符'
})
.label('用户名'),
password: 'string:8-64!'
.pattern(/^(?=.*[a-z])(?=.*[A-Z])(?=.*\d)(?=.*[@$!%*?&]).+$/)
.messages({
'pattern': '密码必须包含大小写字母、数字和特殊字符'
})
.label('密码'),
// 简单字段
age: 'number:18-120',
gender: 'male|female|other'
});
// 验证
const { validate } = require('schema-dsl');
const result = validate(formSchema, {
email: 'user@example.com',
username: 'john_doe',
password: 'Password123!',
age: 25,
gender: 'male'
});
console.log(result.valid); // true
多语言支持
方案1: 全局多语言配置(推荐)
const { Locale } = require('schema-dsl');
// 设置语言
Locale.setLocale('zh-CN');
// 添加自定义语言包
Locale.addLocale('zh-CN', {
'required': '{{#label}}不能为空',
'min': '{{#label}}至少{{#limit}}个字符',
'max': '{{#label}}最多{{#limit}}个字符',
'pattern': '{{#label}}格式不正确',
'format': '请输入有效的{{#label}}'
});
// Schema中使用label
const schema = dsl({
email: 'email!'
.label('邮箱地址'), // 错误消息会自动使用"邮箱地址"
username: 'string:3-32!'
.label('用户名')
});
// 切换语言
Locale.setLocale('en-US'); // 自动切换为英文消息
方案2: 字段级多语言
const schema = dsl({
email: 'email!'
.label('邮箱地址')
.messages({
'format': '请输入有效的邮箱地址',
'required': '邮箱地址不能为空'
})
});
方案3: 运行时动态切换
const { Locale } = require('schema-dsl');
// 根据用户语言偏好切换
function getSchema(locale) {
Locale.setLocale(locale);
return dsl({
email: 'email!'.label(
locale === 'zh-CN' ? '邮箱地址' : 'Email Address'
)
});
}
const zhSchema = getSchema('zh-CN');
const enSchema = getSchema('en-US');
推荐方案: 方案1(全局配置) + 方案2(特殊字段覆盖)
默认安装与卸载
默认安装
root entry 默认安装 String 扩展,用于兼容 v1.1.x 直接字符串链式写法:
const { dsl } = require('schema-dsl');
const schema = dsl({
email: 'email!'.label('邮箱地址')
});
扩展以不可枚举属性挂载到 String.prototype,并在安装时检测同名外部方法;如果发现不是 schema-dsl 自己安装的方法,会拒绝覆盖。
如果你的运行环境在导入 schema-dsl 之前已经扩展了同名方法(例如 String.prototype.label),root entry 会在导入阶段抛出冲突错误,避免静默覆盖外部实现。处理方式是先移除或重命名冲突的外部扩展,再导入 schema-dsl;普通项目通常不会遇到这个场景。
手动禁用
const { uninstallStringExtensions } = require('schema-dsl');
uninstallStringExtensions();
// 之后只能用纯DSL
'email!'.pattern(/custom/) // ❌ 报错
重新启用或自定义安装
const { installStringExtensions } = require('schema-dsl');
installStringExtensions();
// String扩展恢复
'email!'.pattern(/custom/) // ✅ 正常
最佳实践
1. 简单字段用纯DSL
const schema = dsl({
name: 'string:1-50!',
age: 'number:18-120',
role: 'user|admin'
});
2. 复杂字段用链式调用
const schema = dsl({
email: 'email!'
.pattern(/custom/)
.messages({...})
.label('邮箱'),
username: 'string:3-32!'
.pattern(/^\w+$/)
.custom(checkExists)
});
3. 遵循 80/20 法则
JavaScript 中 80% 字段用纯 DSL,20% 复杂字段可直接字符串链式调用;TypeScript 中为了类型提示,复杂字段优先用 dsl() 包裹。
常见问题
Q1: String扩展会污染全局吗?
A: 会扩展 String.prototype,root entry 默认安装以兼容 v1.1.x。副作用已降到较低:扩展方法不可枚举、安装前检测同名冲突、可通过 uninstallStringExtensions() 卸载;如果你需要完全非侵入式写法,卸载后使用 dsl('...') 包裹字符串。
Q2: 性能如何?
A: 性能开销极小(<5%),测试显示反而更快(少了函数调用)。
Q3: TypeScript 支持吗?
A: 完全支持,通过类型定义文件。
Q4: 正确的错误码是什么?
A:
'required' - 必填
'min' / 'max' - 长度/值范围
'pattern' - 正则
'format' - 格式(email/url)
'enum' - 枚举
Q5: 如何支持多语言?
A: 使用 Locale 全局配置(推荐)或字段级 .messages() 覆盖。
相关文档
对应示例文件
示例入口: string-extensions.ts
说明: 覆盖 String.prototype 扩展的安装/卸载、链式 .label() / .messages() / .pattern() 调用,以及校验成功/失败路径。
最后更新: 2026-06-10