[feat] add reach-like functionality to object (#37118) (#37139)

* [feat] add reach-like functionality to object

In #36804 we need to validate a `Partial<HttpConfig>` object which may
or may not have all the required keys attached to it.  This is the type
of use-case for `Joi.reach`, so we should expose a reach-like method on
the object validation class so that you can return the validator for a
specific key on an object.

* [fix] change to validateKey

* [fix] use throw error matcher

* [fix] use same interface for validate

* [fix] change test name]
This commit is contained in:
Todd Kennedy 2019-05-28 09:52:04 -07:00 committed by GitHub
parent c0faaf7e05
commit 00ee70086d
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 27 additions and 0 deletions

View file

@ -199,3 +199,15 @@ test('includes namespace in failure when wrong value type', () => {
expect(() => type.validate(value, {}, 'foo-namespace')).toThrowErrorMatchingSnapshot();
});
test('individual keys can validated', () => {
const type = schema.object({
foo: schema.boolean(),
});
const value = false;
expect(() => type.validateKey('foo', value)).not.toThrowError();
expect(() => type.validateKey('bar', '')).toThrowErrorMatchingInlineSnapshot(
`"bar is not a valid part of this schema"`
);
});

View file

@ -20,6 +20,7 @@
import typeDetect from 'type-detect';
import { AnySchema, internals } from '../internals';
import { Type, TypeOptions } from './type';
import { ValidationError } from '../errors';
export type Props = Record<string, Type<any>>;
@ -31,6 +32,8 @@ export type TypeOf<RT extends Type<any>> = RT['type'];
export type ObjectResultType<P extends Props> = Readonly<{ [K in keyof P]: TypeOf<P[K]> }>;
export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>> {
private props: Record<string, AnySchema>;
constructor(props: P, options: TypeOptions<{ [K in keyof P]: TypeOf<P[K]> }> = {}) {
const schemaKeys = {} as Record<string, AnySchema>;
for (const [key, value] of Object.entries(props)) {
@ -44,6 +47,7 @@ export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>>
.default();
super(schema, options);
this.props = schemaKeys;
}
protected handleError(type: string, { reason, value }: Record<string, any>) {
@ -57,4 +61,15 @@ export class ObjectType<P extends Props = any> extends Type<ObjectResultType<P>>
return reason[0];
}
}
validateKey(key: string, value: any) {
if (!this.props[key]) {
throw new Error(`${key} is not a valid part of this schema`);
}
const { value: validatedValue, error } = this.props[key].validate(value);
if (error) {
throw new ValidationError(error as any, key);
}
return validatedValue;
}
}