Creates type-validation that checks if a value is an object that all its properties are validated with the provided validations.
The following example shows some validations and their expected result
interface Wrapper {
nested: Nested
}
interface Nested {
prop: string
}
// In the following examples, `isNested` is not defined as strict
const isNested = objectOf({
prop: string,
})
const isWrapper = objectOf({
nested: isNested,
})
const isWrapperStrict = objectOf({
nested: isNested,
}, { strict: true })
const isWrapperDeepStrict = isWrapper.strict()
const nested = {
prop: 'a',
}
const extendedNested = {
prop: 'a',
otherProp: 1,
}
const strictlyWrapper = {
nested,
}
const wrapper = {
// But using extended nested object
nested: extendedNested,
}
const extendedWrapper = {
// But using a 'strict' nested value
nested,
other: 'any value',
}
// Non-strict validations pass all objects that are assignable to their validated type.
isWrapper(strictlyWrapper) // true
isWrapper(wrapper) // true
isWrapper(extendedWrapper) // true
// Strict validations pass only object that are assignable to their validated type
// AND have NO extraneous properties.
isWrapperStrict(strictlyWrapper) // true
isWrapperStrict(wrapper) // true
isWrapperStrict(extendedWrapper) // false
// Deep strict validations pass only object that are assignable to their validated type
// AND have NO extraneous properties, and recursively in all their nested objects.
isWrapperDeepStrict(strictlyWrapper) // true
isWrapperDeepStrict(wrapper) // false
isWrapperDeepStrict(extendedWrapper) // falseThe object type that the result type-validation would validate.
Extends: object
Either an object or an array of which all its properties are type-validations.
If propsValidation is an array, the result type-validation also checks that
the validated value is an array that has the exact length of propsValidation.
Type: ObjectOrTupleValidations<T>
If true then the result type-validation also checks that the validated value
does not have additional own keys beyond the validated ones.
Does not affect validations specified by propertySpec.
A TypeValidation<T>.
import { anyOf, objectOf, typeValidatorType } from '@altostra/type-validations'
import { number, string } from '@altostra/type-validations/lib/primitives'
interface MyInterface {
myString: string
}
const isStrictlyMyInterface = objectOf<MyInterface>({
myString: string,
}, { strict: true })
const isIdentifiable = objectOf({
id: anyOf(string, number),
})
const isMyTuple = objectOf([string, number] as const)
console.log(isStrictlyMyInterface[typeValidatorType]) /* {
myString: string
} */
console.log(isIdentifiable[typeValidatorType]) /* {
id: string | number,
[*]: *
} */
console.log(isMyTuple[typeValidatorType]) /* [
string,
number
] */
console.log(isStrictlyMyInterface({ myString: 'a-string' }, console.log)) // true
console.log(isIdentifiable({ id: 'id' }, console.log)) // true
console.log(isIdentifiable({ id: 123, name: 'Smith' }, console.log)) // true
console.log(isMyTuple(['a-string', 123], console.log)) // true
console.log(isStrictlyMyInterface({ myString: 'a-string', id: 5 }, console.log)) /* {
path: [ 'id' ],
reason: "Object has redundant key <'id'>, and failed strict validation",
propertyType: '{\n myString: string\n}'
}
false */
console.log(isIdentifiable({ id: true }, console.log)) /* {
path: [ 'id' ],
reason: 'Value <true> is not a string',
propertyType: 'string'
}
{
path: [ 'id' ],
reason: 'Value <true> is not a number',
propertyType: 'number'
}
false */
console.log(isMyTuple([123, 'a-string'], console.log)) /* {
path: [ 0 ],
reason: 'Value <123> is not a string',
propertyType: 'string'
}
false */
console.log(isMyTuple(['a-string'], console.log)) /* {
path: [ 1 ],
reason: 'Value <undefined> is not a number',
propertyType: 'number'
}
false */
console.log(isMyTuple(['a-string', 123, 5], console.log)) /* {
path: [ 'length' ],
reason: 'Value <3> is not equal to <2>',
propertyType: '2'
}
false */
const myInterfaceIncognito: unknown = { myString: 'a-string' }
const identifiableIncognito: unknown = { id: 5 }
const myTupleIncognito: unknown = ['str', 6]
if (isStrictlyMyInterface(myInterfaceIncognito)) {
console.log(myInterfaceIncognito.myString) // 'a-string'
}
if (isIdentifiable(identifiableIncognito)) {
console.log(identifiableIncognito.id) // 5
}
if (isMyTuple(myTupleIncognito)) {
console.log(myTupleIncognito[1]) // 6
}A non-strict object validation tests all the properties specified by propertySpec.
No matter how many additional properties an object has nor what values they have -
that object would pass non-strict validation:
const anObject = {
a: 1,
b: 2,
}
const isMyObject = objectOf({
a: number,
})
const test = isMyObject(anObject) // trueA strict object validation tests all the properties specified by propertySpec,
just like a non-strict validation does, and also validated that an object does not
have additional properties.
In order to pass a strict validation an object must have all the specified properties,
and nothing else:
const anObject = {
a: 1,
b: 2,
}
const anotherObject = {
a: '1',
}
const theObject {
a: 100,
}
const isMyObject = objectOf({
a: number,
}, { strict: true })
const testAnObject = isMyObject(anObject) // false
const testAnotherObject = isMyObject(anotherObject) // false
const testTheObject = isMyObject(theObject) // trueSpecifying strictness in objectOf options only affect the returned validation,
on the topmost level.
If any of the validated properties is an object-type that is validated using objectOf,
it wouldn't be affected:
// A validator may be declared somewhere like this
const isNestedObject = objectOf({
a: number,
})
// Then used in another object-validation:
const isMyObject = objectOf({
nested: isNestedObject,
}, { strict: true })
const topmostNonStrict = {
nested: {
a: 1,
},
b: 2,
}
const nestedNonStrict = {
nested: {
a: 1,
b: 2,
},
}
const isTopmostStrict = isMyObject(topmostNonStrict) // false
const isNestedStrict = isMyObject(nestedNonStrict) // true! oopsie!There are few ways to control strictness in all validated properties and levels.
If the type-validation you want to make strict (or non-strict) is an object-type-validation
that was created with objectOf, you can simply call validator.strict() to create
a validation that is strict in all its nested properties.
const isMyObject = objectOf({
nested: isNestedObject,
})
const isStrictlyMyObject = isMyObject.strict()
const isNestedStrict = isMyObject(nestedNonStrict) // false, and correctSimilarly, validator.unstrict() would create a validation that is non-strict
in all its nested properties.
// A validator may be declared somewhere like this
const isNestedObject = objectOf({
a: number,
}, { strict: true })
// Then used in another object-validation:
const isMyObject = objectOf({
nested: isNestedObject,
})
const isNonStrictMyObject = isMyObject.unstrict()
const topmostNonStrict = {
nested: {
a: 1,
},
b: 2,
}
const nestedNonStrict = {
nested: {
a: 1,
b: 2,
},
}
const isTopmostStrict = isMyObject(topmostNonStrict) // true
const isNestedStrict = isMyObject(nestedNonStrict) // false! oopsie!
const isNonStrict = isNonStrictMyObject(nestedNonStrict) // trueWhen strictness is needed to be controlled on any kind of TypeValidation,
objectOf.strict(validation) can be used:
const isA = objectOf({
a: number,
})
const isB = objectOf({
b: string,
})
const isAOrB = anyOf(isA, isB)
const a = {
a: 1
}
const b = {
b: '2'
}
const ab = {
...a,
...b,
}
const testA = isAOrB(a) // true
const testB = isAOrB(b) // true
const testAB = isAOrB(ab) // true 🧐
const isAXorB = objectOf.strict(isAOrB)
const testXA = isAXorB(a) // true
const testXB = isAXorB(b) // true
const testXAB = isAXorB(ab) // false 😎Similarly, objectOf.unstrict(validation) can be used to turn off strictness.