├── .gitignore
├── .vscode
└── settings.json
├── README.md
├── tsconfig.json
├── LICENSE
├── package.json
├── eslint.config.ts
├── test
└── index.test.ts
└── src
└── validators.ts
/.gitignore:
--------------------------------------------------------------------------------
1 | node_modules
2 | dist
3 |
--------------------------------------------------------------------------------
/.vscode/settings.json:
--------------------------------------------------------------------------------
1 | {
2 | "eslint.options": {
3 | "flags": ["unstable_ts_config"]
4 | }
5 | }
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # ts-validators
2 |
3 |
4 | A collection of validator functions I frequently use and I'm putting here for sharing purposes. There's now a library version of this repo jet-validators.
5 |
6 |
7 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "module": "commonjs",
5 | "lib": [
6 | "ES2020"
7 | ],
8 | "esModuleInterop": true,
9 | "forceConsistentCasingInFileNames": true,
10 | "strict": true,
11 | "skipLibCheck": true
12 | },
13 | "include": [
14 | "./src",
15 | "./test",
16 | "eslint.config.ts"
17 | ],
18 | "exclude": [
19 | "./node_modules"
20 | ]
21 | }
22 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 Sean Maxwell
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "ts-validators",
3 | "version": "1.0.0",
4 | "description": "A collection of commonly used validator function for TypeScript",
5 | "main": "index.js",
6 | "scripts": {
7 | "test": "vitest",
8 | "clean-install": "rm -rf ./node_modules && rm -r package-lock.json && npm i",
9 | "lint": "eslint --flag unstable_ts_config"
10 | },
11 | "repository": {
12 | "type": "git",
13 | "url": "git+https://github.com/seanpmaxwell/ts-validators.git"
14 | },
15 | "keywords": [
16 | "typescript",
17 | "types",
18 | "validators",
19 | "jet-schema",
20 | "schema",
21 | "type",
22 | "predicate",
23 | "validate",
24 | "check"
25 | ],
26 | "author": "sean maxwell",
27 | "license": "MIT",
28 | "bugs": {
29 | "url": "https://github.com/seanpmaxwell/ts-validators/issues"
30 | },
31 | "homepage": "https://github.com/seanpmaxwell/ts-validators#readme",
32 | "devDependencies": {
33 | "@eslint/js": "^9.11.1",
34 | "@stylistic/eslint-plugin-ts": "^2.8.0",
35 | "@types/eslint__js": "^8.42.3",
36 | "@types/node": "^22.8.1",
37 | "eslint": "^9.11.1",
38 | "eslint-plugin-n": "^17.10.3",
39 | "jiti": "^2.3.3",
40 | "ts-node": "^10.9.2",
41 | "tslib": "^2.8.0",
42 | "typescript": "^5.6.3",
43 | "typescript-eslint": "^8.8.0",
44 | "vitest": "^2.1.4"
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/eslint.config.ts:
--------------------------------------------------------------------------------
1 | import eslint from '@eslint/js';
2 | import tseslint from 'typescript-eslint';
3 | import stylisticTs from '@stylistic/eslint-plugin-ts';
4 | import nodePlugin from 'eslint-plugin-n';
5 |
6 |
7 | export default tseslint.config(
8 | eslint.configs.recommended,
9 | nodePlugin.configs['flat/recommended-script'],
10 | ...tseslint.configs.strictTypeChecked,
11 | ...tseslint.configs.stylisticTypeChecked,
12 | {
13 | ignores: [
14 | '**/node_modules/*',
15 | '**/*.mjs',
16 | '**/*.js',
17 | '**/dist',
18 | ],
19 | },
20 | {
21 | languageOptions: {
22 | parserOptions: {
23 | project: './tsconfig.json',
24 | warnOnUnsupportedTypeScriptVersion: false,
25 | },
26 | },
27 | },
28 | {
29 | plugins: {
30 | '@stylistic/ts': stylisticTs,
31 | },
32 | },
33 | {
34 | files: ['**/*.ts'],
35 | },
36 | {
37 | rules: {
38 | '@typescript-eslint/explicit-member-accessibility': 'warn',
39 | '@typescript-eslint/no-misused-promises': 0,
40 | '@typescript-eslint/no-floating-promises': 0,
41 | '@typescript-eslint/no-confusing-void-expression': 0,
42 | '@typescript-eslint/no-unnecessary-condition': 0,
43 | '@typescript-eslint/restrict-template-expressions': [
44 | 'error', { allowNumber: true },
45 | ],
46 | '@typescript-eslint/restrict-plus-operands': [
47 | 'warn', { allowNumberAndString: true },
48 | ],
49 | '@typescript-eslint/no-unused-vars': 'warn',
50 | '@typescript-eslint/no-unsafe-enum-comparison': 0,
51 | '@typescript-eslint/no-unnecessary-type-parameters': 0,
52 | 'max-len': [
53 | 'warn',
54 | {
55 | 'code': 80,
56 | },
57 | ],
58 | '@stylistic/ts/semi': ['warn'],
59 | '@typescript-eslint/no-non-null-assertion': 0,
60 | '@typescript-eslint/no-unused-expressions': 'warn',
61 | 'comma-dangle': ['warn', 'always-multiline'],
62 | 'no-console': 1,
63 | 'no-extra-boolean-cast': 0,
64 | 'indent': ['warn', 2],
65 | 'quotes': ['warn', 'single'],
66 | 'n/no-process-env': 1,
67 | 'n/no-missing-import': 0,
68 | 'n/no-unpublished-import': 0,
69 | 'prefer-const': 'warn',
70 | },
71 | },
72 | );
73 |
--------------------------------------------------------------------------------
/test/index.test.ts:
--------------------------------------------------------------------------------
1 | import { expect, test } from 'vitest';
2 |
3 | import {
4 | isNulBoolArr,
5 | isEnumVal,
6 | isUndef,
7 | isNull,
8 | isNoU,
9 | isBool,
10 | isOptBool,
11 | isNulBool,
12 | isNishBool,
13 | isBoolArr,
14 | isOptBoolArr,
15 | isNishBoolArr,
16 | isNum,
17 | isOptNum,
18 | isNulNum,
19 | isNishNum,
20 | isNumArr,
21 | isOptNumArr,
22 | isNulNumArr,
23 | isNishNumArr,
24 | isStr,
25 | isOptStr,
26 | isNulStr,
27 | isNishStr,
28 | isStrArr,
29 | isOptStrArr,
30 | isNulStrArr,
31 | isNishStrArr,
32 | isDate,
33 | isOptDate,
34 | isNulDate,
35 | isNishDate,
36 | isDateArr,
37 | isOptDateArr,
38 | isNulDateArr,
39 | isNishDateArr,
40 | isObj,
41 | isOptObj,
42 | isNulObj,
43 | isNishObj,
44 | isObjArr,
45 | isOptObjArr,
46 | isNulObjArr,
47 | isNishObjArr,
48 | isFuncArr,
49 | isOptFuncArr,
50 | isNishFuncArr,
51 | isNulFuncArr,
52 | isNishFunc,
53 | isNulFunc,
54 | isOptFunc,
55 | isFunc,
56 | isColor,
57 | isOptColor,
58 | isNulColor,
59 | isNishColor,
60 | isEmail,
61 | isOptEmail,
62 | isNishEmail,
63 | isNulEmail,
64 | isAlphaNumStr,
65 | isOptAlphaNumStr,
66 | isNulAlphaNumStr,
67 | isNishAlphaNumStr,
68 | isInArr,
69 | isOptOrInArr,
70 | nonNullable,
71 | isBasicObj,
72 | iterateObjEntries,
73 | isEnum,
74 | isNishEnumVal,
75 | isOptEnumVal,
76 | isNulEnumVal,
77 | isNishOrInArr,
78 | isNeStr,
79 | isOptNeStr,
80 | isNulNeStr,
81 | isNishNeStr,
82 | isInRange,
83 | isNishInRange,
84 | isOptInRange,
85 | isNulInRangeArr,
86 | isKeyOf,
87 | isNulKeyOfArr,
88 | transform,
89 | parseObj,
90 | parseObjArr,
91 | parseOptObj,
92 | parseNishObjArr,
93 | isValidNum,
94 | isValidDate,
95 | isValidBool,
96 | isBigInt,
97 | isOptBigInt,
98 | safeJsonParse,
99 | testObj,
100 | isSymbol,
101 | isOptSymbol,
102 | isNulSymbol,
103 | isNishSymbol,
104 | } from '../src/validators';
105 |
106 |
107 | /**
108 | * Test all the basic validators
109 | */
110 | test('test User all default values', () => {
111 |
112 | // Nullables
113 | expect(isUndef(undefined)).toStrictEqual(true);
114 | expect(isNull(null)).toStrictEqual(true);
115 | expect(isNoU(null)).toStrictEqual(true);
116 | expect(isNoU(undefined)).toStrictEqual(true);
117 |
118 | // Booleans
119 | expect(isBool(false)).toStrictEqual(true);
120 | expect(isBool('asdf')).toStrictEqual(false);
121 | expect(isOptBool(false)).toStrictEqual(true);
122 | expect(isOptBool(undefined)).toStrictEqual(true);
123 | expect(isNulBool(false)).toStrictEqual(true);
124 | expect(isNulBool(null)).toStrictEqual(true);
125 | expect(isNishBool(false)).toStrictEqual(true);
126 | expect(isNishBool(null)).toStrictEqual(true);
127 | expect(isNishBool(undefined)).toStrictEqual(true);
128 |
129 | // Is valid boolean
130 | expect(isValidBool(false)).toStrictEqual(true);
131 | expect(isValidBool(true)).toStrictEqual(true);
132 | expect(isValidBool('Yes')).toStrictEqual(true);
133 | expect(isValidBool('no')).toStrictEqual(true);
134 | expect(isValidBool('1')).toStrictEqual(true);
135 | expect(isValidBool('0')).toStrictEqual(true);
136 | expect(isValidBool(1)).toStrictEqual(true);
137 | expect(isValidBool(0)).toStrictEqual(true);
138 | expect(isValidBool('False')).toStrictEqual(true);
139 | expect(isValidBool('tRuE')).toStrictEqual(true);
140 | expect(isValidBool(1234)).toStrictEqual(false);
141 | expect(isValidBool(undefined)).toStrictEqual(false);
142 |
143 | // Boolean Arrays
144 | expect(isBoolArr([false, true, false])).toStrictEqual(true);
145 | expect(isBoolArr([false, true, 'asdf'])).toStrictEqual(false);
146 | expect(isBoolArr(true)).toStrictEqual(false);
147 | expect(isOptBoolArr([false, true, false])).toStrictEqual(true);
148 | expect(isOptBoolArr(undefined)).toStrictEqual(true);
149 | expect(isNulBoolArr([false, true, false])).toStrictEqual(true);
150 | expect(isNulBoolArr(null)).toStrictEqual(true);
151 | expect(isNishBoolArr([false, true, false])).toStrictEqual(true);
152 | expect(isNishBoolArr(null)).toStrictEqual(true);
153 | expect(isNishBoolArr(undefined)).toStrictEqual(true);
154 |
155 | // Numbers
156 | expect(isNum(123)).toStrictEqual(true);
157 | expect(isNum(false)).toStrictEqual(false);
158 | expect(isOptNum(123)).toStrictEqual(true);
159 | expect(isOptNum(undefined)).toStrictEqual(true);
160 | expect(isNulNum(123)).toStrictEqual(true);
161 | expect(isNulNum(null)).toStrictEqual(true);
162 | expect(isNishNum(123)).toStrictEqual(true);
163 | expect(isNishNum(null)).toStrictEqual(true);
164 | expect(isNishNum(undefined)).toStrictEqual(true);
165 |
166 | // Valid numbers
167 | expect(isValidNum('123')).toStrictEqual(true);
168 |
169 | // Number Arrays
170 | expect(isNumArr([1, 2, 3])).toStrictEqual(true);
171 | expect(isNumArr([false, true, '123'])).toStrictEqual(false);
172 | expect(isNumArr(123)).toStrictEqual(false);
173 | expect(isOptNumArr([1, 2 ,3])).toStrictEqual(true);
174 | expect(isOptNumArr(undefined)).toStrictEqual(true);
175 | expect(isNulNumArr([1, 2, 3])).toStrictEqual(true);
176 | expect(isNulNumArr(null)).toStrictEqual(true);
177 | expect(isNishNumArr([1, 2, 3])).toStrictEqual(true);
178 | expect(isNishNumArr(null)).toStrictEqual(true);
179 | expect(isNishNumArr(undefined)).toStrictEqual(true);
180 |
181 | // BigInt
182 | expect(isBigInt(1234567890123456789012345n)).toStrictEqual(true);
183 | expect(isOptBigInt(undefined)).toStrictEqual(true);
184 |
185 | // Ranges
186 | const isValidAge = isInRange(18, 130);
187 | expect(isValidAge(123)).toStrictEqual(true);
188 | expect(isValidAge(5)).toStrictEqual(false);
189 | expect(isValidAge(150)).toStrictEqual(false);
190 | const isPos = isNishInRange(0, null);
191 | expect(isPos(1_000_000)).toStrictEqual(true);
192 | expect(isPos(-1)).toStrictEqual(false);
193 | expect(isPos(undefined)).toStrictEqual(true);
194 | expect(isPos(null)).toStrictEqual(true);
195 | const isNeg = isOptInRange(null, -.000001);
196 | expect(isNeg(-1_000_000)).toStrictEqual(true);
197 | expect(isNeg(.01)).toStrictEqual(false);
198 | expect(isNeg(undefined)).toStrictEqual(true);
199 | expect(isNeg(null)).toStrictEqual(false);
200 | const isValidNums = isNulInRangeArr(-1, 10);
201 | expect(isValidNums([-1, 2, 3])).toStrictEqual(true);
202 | expect(isValidNums([-1, 11, 3])).toStrictEqual(false);
203 | expect(isValidNums([-1, null, 3])).toStrictEqual(false);
204 | expect(isValidNums(2)).toStrictEqual(false);
205 | expect(isValidNums(null)).toStrictEqual(true);
206 |
207 | // Strings
208 | expect(isStr('123')).toStrictEqual(true);
209 | expect(isStr(false)).toStrictEqual(false);
210 | expect(isOptStr('123')).toStrictEqual(true);
211 | expect(isOptStr(undefined)).toStrictEqual(true);
212 | expect(isNulStr('123')).toStrictEqual(true);
213 | expect(isNulStr(null)).toStrictEqual(true);
214 | expect(isNishStr('123')).toStrictEqual(true);
215 | expect(isNishStr(null)).toStrictEqual(true);
216 | expect(isNishStr(undefined)).toStrictEqual(true);
217 |
218 | // Non-Empty Strings
219 | expect(isNeStr('123')).toStrictEqual(true);
220 | expect(isNeStr('')).toStrictEqual(false);
221 | expect(isOptNeStr('123')).toStrictEqual(true);
222 | expect(isOptNeStr(undefined)).toStrictEqual(true);
223 | expect(isNulNeStr('123')).toStrictEqual(true);
224 | expect(isNulNeStr(null)).toStrictEqual(true);
225 | expect(isNishNeStr('123')).toStrictEqual(true);
226 | expect(isNishNeStr('')).toStrictEqual(false);
227 | expect(isNishNeStr(null)).toStrictEqual(true);
228 | expect(isNishNeStr(undefined)).toStrictEqual(true);
229 |
230 | // String Arrays
231 | expect(isStrArr(['1', '2', '3'])).toStrictEqual(true);
232 | expect(isStrArr(['false', '123', true])).toStrictEqual(false);
233 | expect(isStrArr('123')).toStrictEqual(false);
234 | expect(isOptStrArr(['1', '2', '3'])).toStrictEqual(true);
235 | expect(isOptStrArr(undefined)).toStrictEqual(true);
236 | expect(isNulStrArr(['1', '2', '3'])).toStrictEqual(true);
237 | expect(isNulStrArr(null)).toStrictEqual(true);
238 | expect(isNishStrArr(['1', '2', '3'])).toStrictEqual(true);
239 | expect(isNishStrArr(null)).toStrictEqual(true);
240 | expect(isNishStrArr(undefined)).toStrictEqual(true);
241 |
242 | // Symbol
243 | expect(isSymbol(Symbol('foo'))).toStrictEqual(true);
244 | expect(isSymbol(false)).toStrictEqual(false);
245 | expect(isOptSymbol(Symbol('foo'))).toStrictEqual(true);
246 | expect(isOptSymbol(undefined)).toStrictEqual(true);
247 | expect(isNulSymbol(Symbol('foo'))).toStrictEqual(true);
248 | expect(isNulSymbol(null)).toStrictEqual(true);
249 | expect(isNishSymbol(Symbol('foo'))).toStrictEqual(true);
250 | expect(isNishSymbol(null)).toStrictEqual(true);
251 | expect(isNishSymbol(undefined)).toStrictEqual(true);
252 |
253 | // Date
254 | const D1 = new Date();
255 | expect(isDate(D1)).toStrictEqual(true);
256 | expect(isDate(false)).toStrictEqual(false);
257 | expect(isOptDate(D1)).toStrictEqual(true);
258 | expect(isOptDate(undefined)).toStrictEqual(true);
259 | expect(isNulDate(D1)).toStrictEqual(true);
260 | expect(isNulDate(null)).toStrictEqual(true);
261 | expect(isNishDate(D1)).toStrictEqual(true);
262 | expect(isNishDate(null)).toStrictEqual(true);
263 | expect(isNishDate(undefined)).toStrictEqual(true);
264 |
265 | // Valid Dates
266 | expect(isValidDate(1731195800809)).toStrictEqual(true);
267 | expect(isValidDate('2024-11-09T23:43:58.788Z')).toStrictEqual(true);
268 | expect(isValidDate('2024-111-09T23:43:58.788Z')).toStrictEqual(false);
269 | expect(isValidDate(12341234123412342)).toStrictEqual(false);
270 |
271 | // Date Arrays
272 | const D2 = new Date(), D3 = new Date();
273 | expect(isDateArr([D1, D2, D3])).toStrictEqual(true);
274 | expect(isDateArr([D1, D2, '2024-10-30T20:08:36.838Z'])).toStrictEqual(false);
275 | expect(isDateArr(D1)).toStrictEqual(false);
276 | expect(isOptDateArr([D1, D2, D3])).toStrictEqual(true);
277 | expect(isOptDateArr(undefined)).toStrictEqual(true);
278 | expect(isNulDateArr([D1, D2, D3])).toStrictEqual(true);
279 | expect(isNulDateArr(null)).toStrictEqual(true);
280 | expect(isNishDateArr([D1, D2, D3])).toStrictEqual(true);
281 | expect(isNishDateArr(null)).toStrictEqual(true);
282 | expect(isNishDateArr(undefined)).toStrictEqual(true);
283 |
284 | // Obj
285 | const O1 = { val: 1 };
286 | expect(isObj(O1)).toStrictEqual(true);
287 | expect(isObj(false)).toStrictEqual(false);
288 | expect(isOptObj(O1)).toStrictEqual(true);
289 | expect(isOptObj(undefined)).toStrictEqual(true);
290 | expect(isNulObj(O1)).toStrictEqual(true);
291 | expect(isNulObj(null)).toStrictEqual(true);
292 | expect(isNishObj(O1)).toStrictEqual(true);
293 | expect(isNishObj(null)).toStrictEqual(true);
294 | expect(isNishObj(undefined)).toStrictEqual(true);
295 |
296 | // Obj Arrays
297 | const O2 = { val: 2 }, O3 = { val: 3 };
298 | expect(isObjArr([O1, O2, O3])).toStrictEqual(true);
299 | expect(isObjArr([O1, O2, '2024-10-30T20:08:36.838Z'])).toStrictEqual(false);
300 | expect(isObjArr(O1)).toStrictEqual(false);
301 | expect(isOptObjArr([O1, O2, O3])).toStrictEqual(true);
302 | expect(isOptObjArr(undefined)).toStrictEqual(true);
303 | expect(isNulObjArr([O1, O2, O3])).toStrictEqual(true);
304 | expect(isNulObjArr(null)).toStrictEqual(true);
305 | expect(isNishObjArr([O1, O2, O3])).toStrictEqual(true);
306 | expect(isNishObjArr(null)).toStrictEqual(true);
307 | expect(isNishObjArr(undefined)).toStrictEqual(true);
308 |
309 | // Functions
310 | const F1 = () => 1;
311 | expect(isFunc(F1)).toStrictEqual(true);
312 | expect(isFunc(false)).toStrictEqual(false);
313 | expect(isOptFunc(F1)).toStrictEqual(true);
314 | expect(isOptFunc(undefined)).toStrictEqual(true);
315 | expect(isNulFunc(F1)).toStrictEqual(true);
316 | expect(isNulFunc(null)).toStrictEqual(true);
317 | expect(isNishFunc(F1)).toStrictEqual(true);
318 | expect(isNishFunc(null)).toStrictEqual(true);
319 | expect(isNishFunc(undefined)).toStrictEqual(true);
320 |
321 | // Function Arrays
322 | const F2 = () => 2, F3 = () => 3;
323 | expect(isFuncArr([F1, F2, F3])).toStrictEqual(true);
324 | expect(isFuncArr([F1, F2, '2024-10-30T20:08:36.838Z'])).toStrictEqual(false);
325 | expect(isFuncArr(F1)).toStrictEqual(false);
326 | expect(isOptFuncArr([F1, F2, F3])).toStrictEqual(true);
327 | expect(isOptFuncArr(undefined)).toStrictEqual(true);
328 | expect(isNulFuncArr([F1, F2, F3])).toStrictEqual(true);
329 | expect(isNulFuncArr(null)).toStrictEqual(true);
330 | expect(isNishFuncArr([F1, F2, F3])).toStrictEqual(true);
331 | expect(isNishFuncArr(null)).toStrictEqual(true);
332 | expect(isNishFuncArr(undefined)).toStrictEqual(true);
333 |
334 | // Color
335 | expect(isColor('#ffffff')).toStrictEqual(true);
336 | expect(isColor('asdf')).toStrictEqual(false);
337 | expect(isOptColor('#ffffff')).toStrictEqual(true);
338 | expect(isOptColor(undefined)).toStrictEqual(true);
339 | expect(isNulColor('#ffffff')).toStrictEqual(true);
340 | expect(isNulColor(null)).toStrictEqual(true);
341 | expect(isOptColor('#ffffff')).toStrictEqual(true);
342 | expect(isNishColor(undefined)).toStrictEqual(true);
343 | expect(isNishColor(null)).toStrictEqual(true);
344 | expect(isNishColor(undefined)).toStrictEqual(true);
345 |
346 | // Email
347 | expect(isEmail('a@a.com')).toStrictEqual(true);
348 | expect(isEmail('asdf')).toStrictEqual(false);
349 | expect(isOptEmail('a@a.com')).toStrictEqual(true);
350 | expect(isOptEmail(undefined)).toStrictEqual(true);
351 | expect(isNulEmail('a@a.com')).toStrictEqual(true);
352 | expect(isNulEmail(null)).toStrictEqual(true);
353 | expect(isOptEmail('a@a.com')).toStrictEqual(true);
354 | expect(isNishEmail(undefined)).toStrictEqual(true);
355 | expect(isNishEmail(null)).toStrictEqual(true);
356 | expect(isNishEmail(undefined)).toStrictEqual(true);
357 |
358 | // Is Alpha-Numeric String
359 | expect(isAlphaNumStr('asdf1234')).toStrictEqual(true);
360 | expect(isAlphaNumStr('#ffffff')).toStrictEqual(false);
361 | expect(isOptAlphaNumStr('asdf1234')).toStrictEqual(true);
362 | expect(isOptAlphaNumStr(undefined)).toStrictEqual(true);
363 | expect(isNulAlphaNumStr('asdf1234')).toStrictEqual(true);
364 | expect(isNulAlphaNumStr(null)).toStrictEqual(true);
365 | expect(isOptAlphaNumStr('asdf1234')).toStrictEqual(true);
366 | expect(isNishAlphaNumStr(undefined)).toStrictEqual(true);
367 | expect(isNishAlphaNumStr(null)).toStrictEqual(true);
368 | expect(isNishAlphaNumStr(undefined)).toStrictEqual(true);
369 |
370 | // This will make the type '1' | '2' | '3' instead of just string[]
371 | const arr = ['1', '2', '3'] as const;
372 | // const check = isOptOrInArr(arr)
373 |
374 | // Is in Array
375 | expect(isInArr(arr)('1')).toStrictEqual(true);
376 | expect(isInArr(arr)(1)).toStrictEqual(false);
377 | expect(isOptOrInArr(arr)('1')).toStrictEqual(true);
378 | expect(isOptOrInArr(arr)(undefined)).toStrictEqual(true);
379 | expect(isNishOrInArr(arr)(undefined)).toStrictEqual(true);
380 |
381 | enum Scopes {
382 | Public = 'public',
383 | Private = 'private',
384 | }
385 |
386 | enum ScopesAlt {
387 | Public,
388 | Private,
389 | }
390 |
391 | // Enums
392 | expect(isEnumVal(Scopes)('public')).toStrictEqual(true);
393 | expect(isEnumVal(ScopesAlt)(1)).toStrictEqual(true);
394 | expect(isEnumVal(ScopesAlt)('private')).toStrictEqual(false);
395 | expect(isEnum(Scopes)).toStrictEqual(true);
396 | expect(isEnum(ScopesAlt)).toStrictEqual(true);
397 | expect(isOptEnumVal(ScopesAlt)(undefined)).toStrictEqual(true);
398 | expect(isNulEnumVal(ScopesAlt)(null)).toStrictEqual(true);
399 | expect(isNishEnumVal(ScopesAlt)(null)).toStrictEqual(true);
400 | expect(isNishEnumVal(ScopesAlt)(1)).toStrictEqual(true);
401 |
402 | // Non-Nullable
403 | expect(nonNullable(isNulStr)('asdf')).toStrictEqual(true);
404 | expect(nonNullable(isNulStr)(null)).toStrictEqual(false);
405 | expect(nonNullable(isNulStr)(undefined)).toStrictEqual(false);
406 |
407 | // Is Basic Object
408 | expect(isBasicObj({ a: 1, b: 2, c: 3 })).toStrictEqual(true);
409 | expect(isBasicObj([1, 2, 3])).toStrictEqual(false);
410 |
411 | // Check Object entries GOOD
412 | const isStrNumObj = iterateObjEntries>((key, val) =>
413 | isStr(key) && isNum(val));
414 | expect(isStrNumObj({ a: 1, b: 2, c: 3 })).toStrictEqual(true);
415 | expect(isStrNumObj({ a: 1, b: 2, c: 'asdf'})).toStrictEqual(false);
416 |
417 | // Check transform function
418 | const isNumArrWithParse = transform(safeJsonParse, isNumArr);
419 | expect(isNumArrWithParse('[1,2,3]', val => {
420 | expect(isNumArr(val)).toStrictEqual(true);
421 | })).toStrictEqual(true);
422 |
423 | // Check is key of Object
424 | const someObject = {
425 | foo: 'bar',
426 | bada: 'bing',
427 | } as const;
428 |
429 | const isKeyofSomeObject = isKeyOf(someObject);
430 | expect(isKeyofSomeObject('foo')).toStrictEqual(true);
431 | expect(isKeyofSomeObject('bada')).toStrictEqual(true);
432 | expect(isKeyofSomeObject('bing')).toStrictEqual(false);
433 | const isKeyofSomeObjectArr = isNulKeyOfArr(someObject);
434 | expect(isKeyofSomeObjectArr(['bada', 'foo'])).toStrictEqual(true);
435 | expect(isKeyofSomeObjectArr(null)).toStrictEqual(true);
436 | expect(isKeyofSomeObjectArr(['bar', 'foo', 'bing'])).toStrictEqual(false);
437 | });
438 |
439 |
440 | /**
441 | * Test "parseObj()" function
442 | */
443 | test('test "parseObj" function', () => {
444 |
445 | // ** Basic Test **
446 | const parseUser = parseObj({
447 | id: transform(Number, isNum),
448 | name: isStr,
449 | });
450 | const user = parseUser({
451 | id: '5',
452 | name: 'john',
453 | email: '--',
454 | });
455 | expect(user).toStrictEqual({ id: 5, name: 'john' });
456 |
457 | // ** Parse optional object ** //
458 | const parseOptUser = parseOptObj({
459 | id: isNum,
460 | name: isStr,
461 | });
462 | const optUser = parseOptUser({
463 | id: 15,
464 | name: 'joe',
465 | email: '--',
466 | });
467 | const optUser2 = parseOptUser(undefined);
468 | expect(optUser).toStrictEqual({ id: 15, name: 'joe' });
469 | expect(optUser2).toStrictEqual(undefined);
470 |
471 | // ** Array Test ** //
472 | const userArr = [user, { id: 1, name: 'a' }, { id: 2, name: 'b' }],
473 | userArrBad = [user, { id: 1, name: 'a' }, { idd: 2, name: 'b' }];
474 | // Normal array test
475 | const parseUserArr = parseObjArr({
476 | id: isNum,
477 | name: isStr,
478 | });
479 | const parsedUserArr = parseUserArr(userArr),
480 | parsedUserArrBad = parseOptUser(userArrBad);
481 | expect(userArr).toStrictEqual(parsedUserArr);
482 | expect(parsedUserArrBad).toStrictEqual(undefined);
483 | // Nullish or array
484 | const parseNishUserArr = parseNishObjArr({
485 | id: isNum,
486 | name: isStr,
487 | });
488 | const parsedNishUserArr = parseNishUserArr(null);
489 | expect(parsedNishUserArr).toStrictEqual(null);
490 | const parsedNishUserArr2 = parseNishUserArr(userArr);
491 | expect(parsedNishUserArr2).toStrictEqual(userArr);
492 |
493 | // ** Nested Object Test (Good) ** //
494 | const parseUserWithAddr = parseObj({
495 | id: isNum,
496 | name: isStr,
497 | address: {
498 | city: isStr,
499 | zip: isNum,
500 | },
501 | });
502 | const userWithAddr = parseUserWithAddr({
503 | id: 5,
504 | name: 'john',
505 | address: {
506 | city: 'seattle',
507 | zip: 98111,
508 | },
509 | });
510 | expect(userWithAddr).toStrictEqual({
511 | id: 5,
512 | name: 'john',
513 | address: {
514 | city: 'seattle',
515 | zip: 98111,
516 | },
517 | });
518 | expect(userWithAddr.address.zip).toBe(98111);
519 |
520 | // ** Nested Object Test (Bad) ** //
521 | const userWithAddrBad = parseUserWithAddr({
522 | id: 5,
523 | name: 'john',
524 | address: {
525 | city: 'seattle',
526 | zip: '98111',
527 | },
528 | });
529 | expect(userWithAddrBad).toBe(undefined);
530 |
531 | // ** Test parse "onError" function ** //
532 | const parseUserWithError = parseObj({
533 | id: isNum,
534 | name: isStr,
535 | }, (prop, value) => {
536 | expect(prop).toStrictEqual('id');
537 | expect(value).toStrictEqual('5');
538 | });
539 | parseUserWithError({
540 | id: '5',
541 | name: 'john',
542 | });
543 |
544 | // ** Test parseObj "onError" function for array argument ** //
545 | const parseUserArrWithError = parseObjArr({
546 | id: isNum,
547 | name: isStr,
548 | }, (prop, value, index) => {
549 | expect(prop).toStrictEqual('id');
550 | expect(value).toStrictEqual('3');
551 | expect(index).toStrictEqual(2);
552 | });
553 | parseUserArrWithError([
554 | { id: 1, name: '1' },
555 | { id: 2, name: '2' },
556 | { id: '3', name: '3' },
557 | { id: 3, name: '3' },
558 | ]);
559 |
560 | // ** Test "parseObj" when validator throws error ** //
561 | const isStrWithErr = (val: unknown): val is string => {
562 | if (isStr(val)) {
563 | return true;
564 | } else {
565 | throw new Error('Value was not a valid string.');
566 | }
567 | };
568 | const parseUserHandleErr = parseObj({
569 | id: isNum,
570 | name: isStrWithErr,
571 | }, (prop, value, caughtErr) => {
572 | expect(prop).toStrictEqual('name');
573 | expect(value).toStrictEqual(null);
574 | expect(caughtErr).toStrictEqual('Value was not a valid string.');
575 | });
576 | parseUserHandleErr({
577 | id: 5,
578 | name: null,
579 | });
580 | });
581 |
582 |
583 | /**
584 | * Test "testObj" function
585 | */
586 | test('test "testObj" function', () => {
587 |
588 | // Do basic test
589 | const testUser = testObj({
590 | id: isNum,
591 | name: isStr,
592 | address: {
593 | city: isStr,
594 | zip: transform(Number, isNum),
595 | },
596 | });
597 | const result = testUser({
598 | id: 5,
599 | name: 'john',
600 | address: {
601 | city: 'Seattle',
602 | zip: '98109',
603 | },
604 | });
605 | expect(result).toStrictEqual(true);
606 |
607 | // Test combination of "parseObj" and "testObj"
608 | const testCombo = parseObj({
609 | id: isNum,
610 | name: isStr,
611 | address: testObj({
612 | city: isStr,
613 | zip: transform(Number, isNum),
614 | }),
615 | });
616 | const user = testCombo({
617 | id: 5,
618 | name: 'john',
619 | address: {
620 | city: 'Seattle',
621 | zip: '98109',
622 | },
623 | });
624 | expect(user).toStrictEqual({
625 | id: 5,
626 | name: 'john',
627 | address: {
628 | city: 'Seattle',
629 | zip: 98109,
630 | },
631 | });
632 | });
633 |
--------------------------------------------------------------------------------
/src/validators.ts:
--------------------------------------------------------------------------------
1 | /* eslint-disable max-len */
2 |
3 | // **** Variables **** //
4 |
5 | const EMAIL_RGX = /^[^\s@]+@[^\s@]+\.[^\s@]+$/,
6 | COLOR_RGX = new RegExp(/^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/),
7 | ALPHA_NUMERIC = new RegExp('^[a-zA-Z0-9]*$'),
8 | URL_RGX = /^((https?|ftp|smtp):\/\/)?(www.)?[a-z0-9]+(\.[a-z]{2,}){1,3}(#?\/?[a-zA-Z0-9#]+)*\/?(\?[a-zA-Z0-9-_]+=[a-zA-Z0-9-%]+&?)?$/;
9 |
10 |
11 | // **** Types **** //
12 |
13 | export type TEnum = Record;
14 | export type TEmail = `${string}@${string}`;
15 | export type TColor = `#${string}`;
16 | export type TURL = `${string}`;
17 | export type TBasicObj = Record;
18 | type TValidateWithTransform = (arg: unknown, cb?: (arg: T) => void) => arg is T;
19 |
20 | // Add modifiers
21 | type AddNull = (N extends true ? T | null : T);
22 | type AddNullables = (O extends true ? AddNull | undefined : AddNull);
23 | export type AddMods = A extends true ? AddNullables : AddNullables;
24 |
25 |
26 | // **** Functions **** //
27 |
28 | // Nullables
29 | export const isUndef = ((arg: unknown): arg is undefined => arg === undefined);
30 | export const isNull = ((arg: unknown): arg is null => arg === null);
31 | export const isNoU = _orNul(isUndef);
32 |
33 | // Boolean
34 | export const isBool = _checkType('boolean');
35 | export const isOptBool = _orOpt(isBool);
36 | export const isNulBool = _orNul(isBool);
37 | export const isNishBool = _orNul(isOptBool);
38 | export const isBoolArr = _isArr(isBool);
39 | export const isOptBoolArr = _orOpt(isBoolArr);
40 | export const isNulBoolArr = _orNul(isBoolArr);
41 | export const isNishBoolArr = _orNul(isOptBoolArr);
42 |
43 | // Is valid boolean ("true"/"false", true/false, "1/0", "1"/"0", "yes"/"no")
44 | export const isValidBool = _transform(_parseBool, isBool);
45 | export const isOptValidBool = _orOpt(isValidBool);
46 | export const isNulValidBool = _orNul(isValidBool);
47 | export const isNishValidBool = _orNul(isOptValidBool);
48 | export const isValidBoolArr = _isArr(isValidBool);
49 | export const isOptValidBoolArr = _orOpt(isValidBoolArr);
50 | export const isNulValidBoolArr = _orNul(isValidBoolArr);
51 | export const isNishValidBoolArr = _orNul(isOptValidBoolArr);
52 |
53 | // Number
54 | export const isNum = _checkType('number');
55 | export const isOptNum = _orOpt(isNum);
56 | export const isNulNum = _orNul(isNum);
57 | export const isNishNum = _orNul(isOptNum);
58 | export const isNumArr = _isArr(isNum);
59 | export const isOptNumArr = _orOpt(isNumArr);
60 | export const isNulNumArr = _orNul(isNumArr);
61 | export const isNishNumArr = _orNul(isOptNumArr);
62 |
63 | // BigInt
64 | export const isBigInt = _checkType('bigint');
65 | export const isOptBigInt = _orOpt(isBigInt);
66 | export const isNulBigInt = _orNul(isBigInt);
67 | export const isNishBigInt = _orNul(isOptBigInt);
68 | export const isBigIntArr = _isArr(isBigInt);
69 | export const isOptBigIntArr = _orOpt(isBigIntArr);
70 | export const isNulBigIntArr = _orNul(isBigIntArr);
71 | export const isNishBigIntArr = _orNul(isOptBigIntArr);
72 |
73 | // Valid number (is it still a number after doing "Number(arg)", could be a string)
74 | export const isValidNum = _transform(Number, isNum);
75 | export const isOptValidNum = _orOpt(isValidNum);
76 | export const isNulValidNum = _orNul(isValidNum);
77 | export const isNishValidNum = _orNul(isOptValidNum);
78 | export const isValidNumArr = _isArr(isValidNum);
79 | export const isOptValidNumArr = _orOpt(isValidNumArr);
80 | export const isNulValidNumArr = _orNul(isValidNumArr);
81 | export const isNishValidNumArr = _orNul(isOptValidNumArr);
82 |
83 | // Range
84 | export const isInRange = _isInRange(false, false, false);
85 | export const isOptInRange = _isInRange(true, false, false);
86 | export const isNulInRange = _isInRange(false, true, false);
87 | export const isNishInRange = _isInRange(true, true, false);
88 | export const isInRangeArr = _isInRange(false, false, true);
89 | export const isOptInRangeArr = _isInRange(true, false, true);
90 | export const isNulInRangeArr = _isInRange(false, true, true);
91 | export const isNishInRangeArr = _isInRange(true, true, true);
92 |
93 | // String
94 | export const isStr = _checkType('string');
95 | export const isOptStr = _orOpt(isStr);
96 | export const isNulStr = _orNul(isStr);
97 | export const isNishStr = _orNul(isOptStr);
98 | export const isStrArr = _isArr(isStr);
99 | export const isOptStrArr = _orOpt(isStrArr);
100 | export const isNulStrArr = _orNul(isStrArr);
101 | export const isNishStrArr = _orNul(isOptStrArr);
102 |
103 | // NeStr => "Non-Empty String"
104 | export const isNeStr = (arg: unknown): arg is string => (isStr(arg) && arg.length > 0);
105 | export const isOptNeStr = _orOpt(isNeStr);
106 | export const isNulNeStr = _orNul(isNeStr);
107 | export const isNishNeStr = _orNul(isOptNeStr);
108 | export const isNeStrArr = _isArr(isNeStr);
109 | export const isOptNeStrArr = _orOpt(isNeStrArr);
110 | export const isNulNeStrArr = _orNul(isNeStrArr);
111 | export const isNishNeStrArr = _orNul(isOptNeStrArr);
112 |
113 | // Symbol
114 | export const isSymbol = _checkType('symbol');
115 | export const isOptSymbol = _orOpt(isSymbol);
116 | export const isNulSymbol = _orNul(isSymbol);
117 | export const isNishSymbol = _orNul(isOptSymbol);
118 | export const isSymbolArr = _isArr(isSymbol);
119 | export const isOptSymbolArr = _orOpt(isSymbolArr);
120 | export const isNulSymbolArr = _orNul(isSymbolArr);
121 | export const isNishSymbolArr = _orNul(isOptSymbolArr);
122 |
123 | // Date
124 | export const isDate = (arg: unknown): arg is Date => arg instanceof Date;
125 | export const isOptDate = _orOpt(isDate);
126 | export const isNulDate = _orNul(isDate);
127 | export const isNishDate = _orNul(isOptDate);
128 | export const isDateArr = _isArr(isDate);
129 | export const isOptDateArr = _orOpt(isDateArr);
130 | export const isNulDateArr = _orNul(isDateArr);
131 | export const isNishDateArr = _orNul(isOptDateArr);
132 |
133 | // Valid date (is it a valid date after calling "new Date()", could be a string or number)
134 | export const isValidDate = _transform((arg: unknown) => new Date(arg as Date), _isValidDate);
135 | export const isOptValidDate = _orOpt(isValidDate);
136 | export const isNulValidDate = _orNul(isValidDate);
137 | export const isNishValidDate = _orNul(isOptValidDate);
138 | export const isValidDateArr = _isArr(isValidDate);
139 | export const isOptValidDateArr = _orOpt(isValidDateArr);
140 | export const isNulValidDateArr = _orNul(isValidDateArr);
141 | export const isNishValidDateArr = _orNul(isOptValidDateArr);
142 |
143 | // Object
144 | export const isObj = _checkType