Both validate and validateAsync functions return the same result object with four properties.

/**
 * Result of the validation.
 *
 * @param valid true if the whole object is validated successfully
 * @param errors validation results with errors @see FieldValidationResult
 * @param missing field validations that are missing on the test object  @see FieldValidationResult
 * @param struct  object that represents the structure of the validation object with all test results.
 */
export interface ValidationResult<T = any> {
  valid: boolean
  errors: FieldValidationResult[]
  missing: FieldValidationResult[]
  struct: DeepValidated<T>
}

const test = {
    name:'Same'
    lastName:'Fisher'
}

const validators = {
    name:checkName,
    lastName:[checkStringLength,checkLastName],//array of validators
    profession:[checkProfession]
}
// checkName,checkLastName,checkStringLengthand,checkProfession are validation objects (more on that later)
const result = validate(validators,test)

Let’s say that name is validated successfully, lastName failed validation and profession field does not exist on the tested object so it is missing (but that will not cause the final result to be invalid because that field is not marked as required via validator)

This would be the result:

const result = {
  valid: false, // failed validaton,
  errors: [errorObj], // same as result.struct.lastName
  missing: [missingObj], //same as result.struct.profession
  struct: {
    name: {
      error: false,
      missing: false,
      value: 'Sam',
      field: 'name',
      path: 'name',
      message: '', //empty message because test was successful
    },
    lastName: {
      error: true,
      missing: false,
      value: 'Fisher',
      field: 'lastName',
      path: 'lastName', //deeply nested path could look like this: person.profile.lastName
      message: `Field:'${path}' with value:${value} failed validation.`,
    },
    profession: {
      error: false, // false because it is not required
      missing: true, // because there is no `profession` field on the `person` object
      value: null, //  there is no value
      field: 'profession',
      path: 'profession',
      message: `Field:'${path}' not provided.`,
    },
  },
}

As you can see there is a pattern to the struct object properties. For every field that exists on the validators object, this structure will be returned:

/**
 * Result object for single field validation.
 *
 * @param error  true if validation failed
 * @param missing  true if the field to be validated is missing from the test object and the field is required
 * @param value  value of the field that was tested
 * @param field object field name
 * @param path  full path to the field on the object e.g user.profile.address
 * @param message  field validation message
 */
export interface FieldValidationResult {
  error: boolean
  missing: boolean
  field: string
  path: string
  message: string
  value: any
}

All errors in the validation result are also conveniently stored in the errors array.

// same object as result.struct.occupation
result.errors[0] = {
  error: true,
  missing: true,
  value: null,
  field: 'occupation',
  path: 'occupation',
  message: 'Field "occupation" not provided',
}
// same object as result.struct.location.city
result.errors[1] = {
  error: true,
  missing: false,
  value: 'Montreal099',
  field: 'city',
  path: 'location.city',
  message: 'Field "location.city" is not a valid city in Canada',
}

Missing fields are stored in the missing array.

// same object as result.struct.occupation
result.missing[0] = {
    error:true,
    missing:true, // field is not present on the tested object
    value:null,
    field:'occupation',
    path:'occupation'
    message:'Field "occupation" not provided'
}

You will notice that the occupation object is stored both in the errors and in the missing array on the result object. This is because occupation field is missing but it is required to exist, that makes it an error. By default validation fields are not required to exist on the object that is being tested. Only when they marked as required test object will fail validation.

Read more about required property