{"id":23452806,"url":"https://github.com/sijiecai/ts-class-validator","last_synced_at":"2025-04-13T21:43:50.567Z","repository":{"id":57380564,"uuid":"156826726","full_name":"SijieCai/ts-class-validator","owner":"SijieCai","description":"Declarative typescript validator with nested logic operator support.","archived":false,"fork":false,"pushed_at":"2019-03-23T09:47:15.000Z","size":162,"stargazers_count":12,"open_issues_count":0,"forks_count":2,"subscribers_count":2,"default_branch":"master","last_synced_at":"2025-03-27T12:08:16.664Z","etag":null,"topics":["behavior","declarative","decorators","metaprogramming","typescript","validation","validator"],"latest_commit_sha":null,"homepage":null,"language":"TypeScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/SijieCai.png","metadata":{"files":{"readme":"README-zh_CN.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2018-11-09T07:36:22.000Z","updated_at":"2023-04-18T12:52:09.000Z","dependencies_parsed_at":"2022-09-05T14:31:19.399Z","dependency_job_id":null,"html_url":"https://github.com/SijieCai/ts-class-validator","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SijieCai%2Fts-class-validator","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SijieCai%2Fts-class-validator/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SijieCai%2Fts-class-validator/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/SijieCai%2Fts-class-validator/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/SijieCai","download_url":"https://codeload.github.com/SijieCai/ts-class-validator/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248788868,"owners_count":21161726,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["behavior","declarative","decorators","metaprogramming","typescript","validation","validator"],"created_at":"2024-12-24T01:27:33.198Z","updated_at":"2025-04-13T21:43:50.544Z","avatar_url":"https://github.com/SijieCai.png","language":"TypeScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# ts-class-validator\n支持嵌套逻辑操作符的声明式TypeScript验证器\n\n## 安装\n\n```\nnpm install ts-class-validator --save\n```\n\n## 使用\n\n``` typescript\nimport { validate, is, not, and, or, each, isClass, validateGet, mixins } from 'ts-class-validator';\n\n```\n\n### 基本类型验证\n\n每个validate默认不是必须的，除非你将`is.required()`放在顶部，否则`null` 和 `undefined`总是会通过验证\n\n``` typescript \nclass PrimitiveClass {\n  @validate(\n    is.length(4, 10),\n    is.contains('111')\n  )\n  name: string;\n\n  @validate(\n    is.required(),\n    is.int({min: 1})\n  )\n  age: number;\n}\n\nisClass(PrimitiveClass, { name: '111abced', age: 5 }) // true\nisClass(PrimitiveClass, { name: '360', age: 5 }) // 'error message here'\n\nvalidateGet(PrimitiveClass, { name: '111abced', age: '5' }) \n// { instance: PrimitiveClass { name: '111abced', age: 5 } }\nvalidateGet(PrimitiveClass, { name: '360', age: 5 }) \n// { message: 'error message here' }\n \n```\n\n\n\n### 数组验证\n\n使用 `each` 验证数组，你也可以嵌套 `each` 来验证二维数组。\n\n``` typescript \nclass ArrayClass {\n  @validate(\n    is.required(),\n    each(\n      is.required(),\n      is.int()\n    )\n  )\n  value: number[];\n\n  @validate(\n    each(\n      each(\n        is.int();\n      )\n    )\n  )\n  value2: number[][];\n}\n\nvalidateGet(ArrayClass, {value: [1,2,3]})  // { instance: ArrayClass { value: [1,2,3] } }\n\nvalidateGet(ArrayClass, {value: [1,2,null]}) // { message: 'error message here' }\n\nvalidateGet(ArrayClass, {value: '1,2,3,4'})\n// { instance: ArrayClass {value: [1,2,3,4] } }\n\nvalidateGet(ArrayClass, {value: '1,2,3,4'}, {parseArray: false}) \n// { instance: ArrayClass {value: '1,2,3,4'} }\n\nvalidateGet(ArrayClass, {value: '1,2,3,4'}, {parseNumber: false}) \n// { instance: ArrayClass {value: ['1','2','3','4']} }\n\nvalidateGet(ArrayClass, {value: '1,2', value2: [[1, 2],[3, '4']]})\n// { instance: ArrayClass {value: ['1','2'], value2: [[1,2], [3,4]]} }\n\n```\n\n### 嵌套class验证\n\n``` typescript \n\nclass NestedClass {\n  @validate(is.class(IdClass))\n  id: IdClass;\n}\n\nclass DeeplyNestedClass {\n  @validate(is.class(NestedClass))\n  value: NestedClass;\n}\n\n```\n\n### 逻辑操作符\n\n你可以使用 `and`, `or` 逻辑操作符，他们也可以在嵌套中使用。\n所有验证规则都可以指定 `onlyIf` 来选择开启或关闭这个验证。\n\n``` typescript\nclass AndOrClass {\n  @validate(or(\n    is.in([1, 2, 3]),\n    and(\n      is.in([4, 5, 6]),\n      is.divisibleBy(2)\n    )\n  ))\n  value: number;\n}\n\nclass OnlyIfClass {\n  @validate(\n    is.in([1, 2, 3]).onlyIf(\n      (target: object, key: string) =\u003e target['value2'] !== undefined\n    )\n  )\n  status: number;\n  @validate(is.int())\n  value2: number;\n}\n```\n\n### 自定义错误信息\n``` typescript\nclass CustomizeMessageClass {\n  @validate(\n    is.required().message('field is required!!'),\n    is.equals('some value').message('field must equals to some value!!'),\n    or(\n      is.in([1, 2]),\n      is.equals(3)\n    ).message('field must be 1,2 or 3, just kidding LOL.')\n  )\n  field: string;\n}\n```\n\n### 继承验证类\n\n``` typescript \n\nclass IdClass {\n  @validate(is.required(), is.int())\n  id: number;\n\n  getId() {return 'prefix-' + this.id ; }\n}\n \nclass ExtendClass extends IdClass {\n  name: string; \n}\n\nlet instance = validateGet(MixinClass, {id: 1, name: 'name'}).instance;\nconsole.log(instance.getId()); // 'prefix-1'\n\n```\n\n\n### 混合验证类\n\n``` typescript \n\nclass IdClass {\n  @validate(is.required(), is.int())\n  id: number;\n\n  getId() {return 'prefix-' + this.id ; }\n}\n\nclass NameClass {\n  @validate(is.required(), is.length(3,10))\n  name: string;\n\n  @validate() // validate without rules is used to whitelisting a field for validateGet\n  whitelist: any\n}\n\n@mixins(IdClass, NameClass)\nclass MixinClass implements IdClass, NameClass {\n  name: string;\n  id: number[];\n  getId: ()=\u003estring\n}\n\nlet instance = validateGet(MixinClass, {id: 1, name: 'name'}).instance;\nconsole.log(instance.getId()); // 'prefix-1'\n\n\n```\n\n### 验证规则\n\n`is` 和 `not` 是内建的规则生成器生成的，它们支持所有 [validator.js](https://github.com/chriso/validator.js)\n的静态方法（除 sanitizer），此外我们增加了以下方法：\n- func(customValidator: (target: any, key: string) =\u003e boolean | string): 定义一个自定义验证器逻辑，你可以在这里写任何东西。\n- class(TClass: new () =\u003e any, fieldsPattern?: string): 和isClass类似, 定义一个嵌套的class类型。\n- required(): 所有其它验证都通过时，value为 `null` 或者 `undefined` 不能通过验证.\n- tripleEquals(value: any): 比较 target === value\n- doubleEquals(value: any): 比较 target == value\n\n### 创建你自己的规则生成器\n\n你可以定义你自己的规则生成器返回一个规则，它能够被组合（compose）和重用（reused），例如，你想要在JSON解析时验证一些字段，你可以这样做：\n\n``` typescript\n\nclass Person {/* .... */}\n\nclass SomeClass {\n  @validate(\n    jsonParse(\n      is.class(Person)\n    ).message('person is not a valid JSON')\n  )\n  person: Person;\n}\n\nvalidateGet(SomeClass, {person: '{\"person\":{\"name\":\"\",\"age\":40}}'}, {parseJSON: true})\n// SomeClass { person: Person {name: '', age: 40} }\n\n```\n\n实现 jsonParse ：\n\n``` typescript\nimport { Rule, and } from 'ts-class-validation';\nfunction jsonParse(...rules: Rule[]) {\n  return new Rule(\n    function validate(target: object, key: string) {\n      let value = target[key];\n\n      try { value = JSON.parse(value); }\n      catch (e) { return false; }\n\n      target = Object.assign({}, target, { [key]: value });\n\n      return and(...rules).validate(target, key);\n    },\n    function getMessage(target, key) { return `target.${key} is not a validate json` },\n    function validateGetParser(value, options) {\n      if (options.parseJSON) { // parseJSON passed in by validateGet(a, b, options)\n        return JSON.parse(value);\n      }\n      return value;\n    }\n  );\n}\n```\n\n### validateGet 选项\n`validateGet` 接收三个可选参数\n\n``` typescript\n\ninterface ValidateGetOptions {\n  filterUnvalidateFields?: boolean; // default true\n  parseNumber?: boolean;      // default true\n  parseArray?: boolean;       // default true\n  [name: string]: any         // for user defined rule \n}\n\n```\n## 本地化\n\n每个失败的验证将显示一条内置的错误信息，你可以用 `.message()` 方法重写每个规则的错误信息，或者你可以重写默认错误信息。\n\n``` typescript\nimport { setErrorMessage } from 'ts-class-validator';\nsetErrorMessage({\n  contains: {\n    is: (target: object, key: string, ...rest: any[]) =\u003e `customized: ${target[key]} contains ${rest.join(', ')}`,\n    not: (target: object, key: string, ...rest: any[]) =\u003e `customized: ${target[key]} not contains ${rest.join(', ')}`\n  },\n  after: {\n    is: (target: object, key: string, ...rest: any[]) =\u003e `customized: ${target[key]} date is after date ${rest.join(', ')}`,\n    not: (target: object, key: string, ...rest: any[]) =\u003e `customized: ${target[key]} date is not after date ${rest.join(', ')}`\n  },\n  // other settings\n})\n\n```\n\n## 异步支持\n\n现在不支持异步的验证方法！\n\n异步验证混合同步的可能会导致性能问题，为什么？大多是时候异步验证很耗时，我们通常想同步验证成功后再一个接一个或者并行做异步，这取决于应用的情况，但如果我们设计接口时去支持所有的情景，最终可能会导致它非常丑陋。\n\n如果你有更好的想法，欢迎告诉我。","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsijiecai%2Fts-class-validator","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fsijiecai%2Fts-class-validator","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fsijiecai%2Fts-class-validator/lists"}