Skip to content

Commit 10b088b

Browse files
committed
refactor: refactor type-utils & DRY shaped and of validator
1 parent 5c954f4 commit 10b088b

3 files changed

Lines changed: 68 additions & 73 deletions

File tree

src/createErrors.ts

Lines changed: 44 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ import {
66
ObjectKeys,
77
toObj,
88
shouldAddToResult,
9+
isArray,
910
} from './utils';
1011
import {
1112
BooleanValidator,
@@ -20,6 +21,7 @@ import {
2021
UnionValidator,
2122
Validator,
2223
} from './validatorTypes';
24+
import { InferResult, InferCallbackResult } from './type-utils';
2325
import { TYPEERR } from './constants';
2426
import invariant from 'tiny-invariant';
2527

@@ -37,26 +39,42 @@ function enterNode(validator: Validator, value: unknown, eager = false) {
3739
return fn(validator, value, eager);
3840
}
3941

40-
type InferCallbackResult<V extends Validator> = V extends
41-
| StringValidator
42-
| NumberValidator
43-
| BooleanValidator
44-
| ConstantValidator<any>
45-
| UnionValidator<any>
46-
? string
47-
: V extends ListValidator<infer U>
48-
? { [key in number]?: InferCallbackResult<U[key]> }
49-
: V extends ListofValidator<infer U>
50-
? { [key: number]: InferCallbackResult<U> | undefined }
51-
: V extends RecordValidator<infer U>
52-
? { [key in keyof U]?: InferCallbackResult<U[key]> }
53-
: V extends RecordofValidator<infer U>
54-
? { [key: string]: InferCallbackResult<U> | undefined }
55-
: never;
56-
57-
type InferResult<S extends Schema> = {
58-
[key in keyof S]?: InferCallbackResult<S[key]>;
59-
};
42+
function parseShapeValidator(
43+
validator: RecordValidator<any> | ListValidator<any[]>,
44+
value: unknown,
45+
eager = false
46+
) {
47+
const shape = toObj(validator).shape;
48+
const keys = ObjectKeys(shape);
49+
const values = toObj(value);
50+
const result: Record<string, any> = {};
51+
for (let i = 0; i < keys.length; i++) {
52+
const currentResult = enterNode(shape[keys[i]], values[keys[i]]);
53+
if (shouldAddToResult(currentResult)) {
54+
result[keys[i]] = currentResult;
55+
if (eager) return result;
56+
}
57+
}
58+
return normalizeResult(result);
59+
}
60+
61+
function parseOfValidator(
62+
validator: RecordofValidator<any> | ListofValidator<any>,
63+
value: unknown,
64+
eager = false
65+
) {
66+
const values = toObj(value);
67+
const keys = ObjectKeys(values);
68+
const result: Record<string, any> = {};
69+
for (let i = 0; i < keys.length; i++) {
70+
const currentResult = enterNode(validator.of, values[keys[i]]);
71+
if (shouldAddToResult(currentResult)) {
72+
result[keys[i]] = currentResult;
73+
if (eager) return result;
74+
}
75+
}
76+
return normalizeResult(result);
77+
}
6078

6179
const validators = {
6280
string(validator: StringValidator, value: unknown) {
@@ -117,65 +135,23 @@ const validators = {
117135
},
118136
list<T extends Validator[]>(validator: ListValidator<T>, value: unknown, eager = false) {
119137
if (shouldSkipValidation(value, validator)) return null;
120-
if (!Array.isArray(value)) return TYPEERR;
121-
const shape = toObj(validator).shape;
122-
const keys = ObjectKeys(shape);
123-
const values = toObj(value);
124-
const result: Record<string, any> = {};
125-
for (let i = 0; i < keys.length; i++) {
126-
const currentResult = enterNode(shape[keys[i]], values[keys[i]]);
127-
if (shouldAddToResult(currentResult)) {
128-
result[keys[i]] = currentResult;
129-
if (eager) return result;
130-
}
131-
}
132-
return normalizeResult(result);
138+
if (!isArray(value)) return TYPEERR;
139+
return parseShapeValidator(validator, value, eager);
133140
},
134141
listof<T extends Validator>(validator: ListofValidator<T>, value: unknown, eager = false) {
135142
if (shouldSkipValidation(value, validator)) return null;
136-
if (!Array.isArray(value)) return TYPEERR;
137-
const values = toObj(value);
138-
const keys = ObjectKeys(values);
139-
const result: Record<string, any> = {};
140-
for (let i = 0; i < keys.length; i++) {
141-
const currentResult = enterNode(validator.of, values[keys[i]]);
142-
if (shouldAddToResult(currentResult)) {
143-
result[keys[i]] = currentResult;
144-
if (eager) return result;
145-
}
146-
}
147-
return normalizeResult(result);
143+
if (!isArray(value)) return TYPEERR;
144+
return parseOfValidator(validator, value, eager);
148145
},
149146
record<T extends Schema>(validator: RecordValidator<T>, value: unknown, eager = false) {
150147
if (shouldSkipValidation(value, validator)) return null;
151148
if (!isPlainObject(value)) return TYPEERR;
152-
const shape = toObj(validator).shape;
153-
const keys = ObjectKeys(shape);
154-
const values = toObj(value);
155-
const result: Record<string, any> = {};
156-
for (let i = 0; i < keys.length; i++) {
157-
const currentResult = enterNode(shape[keys[i]], values[keys[i]]);
158-
if (shouldAddToResult(currentResult)) {
159-
result[keys[i]] = currentResult;
160-
if (eager) return result;
161-
}
162-
}
163-
return normalizeResult(result);
149+
return parseShapeValidator(validator, value, eager);
164150
},
165151
recordof<T extends Validator>(validator: RecordofValidator<T>, value: unknown, eager = false) {
166152
if (shouldSkipValidation(value, validator)) return null;
167153
if (!isPlainObject(value)) return TYPEERR;
168-
const values = toObj(value);
169-
const keys = ObjectKeys(values);
170-
const result: Record<string, any> = {};
171-
for (let i = 0; i < keys.length; i++) {
172-
const currentResult = enterNode(validator.of, values[keys[i]]);
173-
if (shouldAddToResult(currentResult)) {
174-
result[keys[i]] = currentResult;
175-
if (eager) return result;
176-
}
177-
}
178-
return normalizeResult(result);
154+
return parseOfValidator(validator, value, eager);
179155
},
180156
};
181157

src/type-utils.ts

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010
Schema,
1111
ConstantValidator,
1212
UnionValidator,
13+
Validator,
1314
} from './validatorTypes';
1415

1516
type InferTypeWithOptional<T, U> = T extends O<T> ? U | undefined : U;
@@ -43,3 +44,24 @@ type InferDataType<T> = T extends UnionValidator<infer U>
4344
export type DataFrom<S extends Schema> = {
4445
[K in keyof S]: InferDataType<S[K]>;
4546
};
47+
48+
export type InferCallbackResult<V extends Validator> = V extends
49+
| StringValidator
50+
| NumberValidator
51+
| BooleanValidator
52+
| ConstantValidator<any>
53+
| UnionValidator<any>
54+
? string
55+
: V extends ListValidator<infer U>
56+
? { [key in number]?: InferCallbackResult<U[key]> }
57+
: V extends ListofValidator<infer U>
58+
? { [key: number]: InferCallbackResult<U> | undefined }
59+
: V extends RecordValidator<infer U>
60+
? { [key in keyof U]?: InferCallbackResult<U[key]> }
61+
: V extends RecordofValidator<infer U>
62+
? { [key: string]: InferCallbackResult<U> | undefined }
63+
: never;
64+
65+
export type InferResult<S extends Schema> = {
66+
[key in keyof S]?: InferCallbackResult<S[key]>;
67+
};

src/utils.ts

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
export const ObjectKeys = Object.keys.bind(Object);
2+
export const isArray = (value: unknown): value is any[] => Array.isArray(value);
23
export const isBool = (value: unknown): value is boolean => typeof value == 'boolean';
34
export const isString = (value: unknown): value is string => typeof value == 'string';
45
export const isNumber = (value: unknown): value is number =>
@@ -24,9 +25,5 @@ export function shouldAddToResult(res: unknown) {
2425
}
2526

2627
export function toObj(value: any) {
27-
return Array.isArray(value)
28-
? { ...value }
29-
: isPlainObject(value)
30-
? value
31-
: ({} as Record<string, any>);
28+
return isArray(value) ? { ...value } : isPlainObject(value) ? value : ({} as Record<string, any>);
3229
}

0 commit comments

Comments
 (0)