TypeBox 
@feathersjs/typebox allows to define JSON schemas with TypeBox, a JSON schema type builder with static type resolution for TypeScript.
Note
For additional information also see the TypeBox documentation.
Usage 
The module exports all of TypeBox functionality with additional support for query schemas and validators. The following is an example for defining the message schema from the guide using TypeBox:
import { Type } from '@feathersjs/typebox'
import type { Static } from '@feathersjs/typebox'
const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String(),
    createdAt: Type.Number(),
    userId: Type.Number()
  },
  { $id: 'Message', additionalProperties: false }
)
type Message = Static<typeof messageSchema>Result and data schemas 
A good approach to define schemas in a Feathers application is to create the main schema first. This is usually the properties that are in the database and things like associated entries. Then we can get the data schema by e.g. picking the properties a client submits using Type.Pick
import { Type } from '@feathersjs/typebox'
import type { Static } from '@feathersjs/typebox'
const userSchema = Type.Object(
  {
    id: Type.Number(),
    email: Type.String(),
    password: Type.String(),
    avatar: Type.Optional(Type.String())
  },
  { $id: 'User', additionalProperties: false }
)
type User = Static<typeof userSchema>
// Pick the data for creating a new user
const userDataSchema = Type.Pick(userSchema, ['email', 'password'])
type UserData = Static<typeof userDataSchema>
const messageSchema = Type.Object(
  {
    id: Type.Number(),
    text: Type.String(),
    createdAt: Type.Number(),
    userId: Type.Number(),
    // Reference the user
    user: Type.Ref(userSchema)
  },
  { $id: 'Message', additionalProperties: false }
)
type Message = Static<typeof messageSchema>
// Pick the data for creating a new message
const messageDataSchema = Type.Pick(messageSchema, ['text'])
type MessageData = Static<typeof messageDataSchema>Query schemas 
querySyntax 
querySyntax(definition, extensions, options) returns a schema to validate the Feathers query syntax for all properties in a TypeBox definition.
import { querySyntax } from '@feathersjs/typebox'
// Schema for allowed query properties
const messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {
  additionalProperties: false
})
const messageQuerySchema = querySyntax(messageQueryProperties)
type MessageQuery = Static<typeof messageQuerySchema>Additional special query properties that are not already included in the query syntax like $ilike can be added like this:
import { querySyntax } from '@feathersjs/typebox'
// Schema for allowed query properties
const messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {
  additionalProperties: false
})
const messageQuerySchema = Type.Intersect(
  [
    // This will additionally allow querying for `{ name: { $ilike: 'Dav%' } }`
    querySyntax(messageQueryProperties, {
      name: {
        $ilike: Type.String()
      }
    }),
    // Add additional query properties here
    Type.Object({})
  ],
  { additionalProperties: false }
)To allow additional query properties outside of the query syntax use the intersection type:
import { querySyntax } from '@feathersjs/typebox'
// Schema for allowed query properties
const messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {
  additionalProperties: false
})
const messageQuerySchema = Type.Intersect(
  [
    querySyntax(messageQueryProperties),
    Type.Object({
      isActive: Type.Boolean()
    })
  ],
  { additionalProperties: false }
)
type MessageQuery = Static<typeof messageQuerySchema>queryProperty 
queryProperty(definition) returns a schema for the Feathers query syntax for a single property.
Validators 
The following functions are available to get a validator function from a TypeBox schema.
note
See the validators chapter for more information on validators and validator functions.
getDataValidator 
getDataValidator(definition, validator) returns validators for the data of create, update and patch service methods. You can either pass a single definition in which case all properties of the patch schema will be optional or individual validators for create, update and patch.
import { Ajv } from '@feathersjs/schema'
import { Type, getDataValidator } from '@feathersjs/typebox'
import type { Static } from '@feathersjs/typebox'
const userSchema = Type.Object(
  {
    id: Type.Number(),
    email: Type.String(),
    password: Type.String(),
    avatar: Type.Optional(Type.String())
  },
  { $id: 'User', additionalProperties: false }
)
type User = Static<typeof userSchema>
// Pick the data for creating a new user
const userDataSchema = Type.Pick(userSchema, ['email', 'password'])
const dataValidator = new Ajv()
const userDataValidator = getDataValidator(userDataSchema, dataValidator)
// For more granular control
const userDataValidator = getDataValidator(
  {
    create: userDataSchema,
    update: userDataSchema,
    patch: Type.Partial(userDataSchema)
  },
  dataValidator
)getValidator 
getValidator(definition, validator) returns a single validator function for a TypeBox schema.
import { Ajv } from '@feathersjs/schema'
import { Type, getValidator } from '@feathersjs/typebox'
// Schema for allowed query properties
const messageQueryProperties = Type.Pick(messageSchema, ['id', 'text', 'createdAt', 'userId'], {
  additionalProperties: false
})
const messageQuerySchema = querySyntax(messageQueryProperties)
type MessageQuery = Static<typeof messageQuerySchema>
// Since queries can be only strings we can to coerce them
const queryValidator = new Ajv({
  coerceTypes: true
})
const messageQueryValidator = getValidator(messageQuerySchema, queryValidator)Validating Dates 
When validating dates sent from the client, the most spec-compliant solution is to use the ISO8601 format. For example, SQLite date values are strings in the ISO8601 format, which is YYYY-MM-DDTHH:MM:SS.SSS. The character between the date and time formats is generally specified as the letter T, as in 2016-01-01T10:20:05.123. For date values, you implement this spec with Type.String and not Type.Date.
When using AJV you can validate this format with the ajv-formats package, which the Feathers CLI installs for you. Using it with @feathersjs/typebox looks like this:
const userSchema = Type.Object(
  {
    createdAt: Type.String({ format: 'date-time' })
  },
  { $id: 'User', additionalProperties: false }
)See the @feathersjs/mongodb docs for more information on validating dates with MongoDB.
Types 
TypeBox provides a set of functions that allow you to compose JSON Schema similar to how you would compose static types with TypeScript. Each function creates a JSON schema fragment which can compose into more complex types. The schemas produced by TypeBox can be passed directly to any JSON Schema-compliant validator, or used to reflect runtime metadata for a type.
Standard 
These are the standard TypeBox types. Each section shows equivalent code in three formats:
- TypeBox
- TypeScript type
- JSON Schema
The following information comes from the TypeBox documentation. It has been formatted to make it easier to copy/paste examples.
Primitive Types 
Primitive type utilities create schemas for individual values.
Any 
Creates a schema that will always pass validation. It's the equivalent of TypeScript's any type.
const T = Type.Any()type T = anyconst T = {}Unknown 
Similar to any, it creates a schema that will always pass validation. It's the equivalent of TypeScript's unknown type.
const T = Type.Unknown()type T = unknownconst T = {}String 
Creates a string schema and type. Type.String will generally be used for validating dates sent from clients, as well. See Validating Dates.
const T = Type.String()type T = stringconst T = {
  type: 'string'
}String Formats Bundled 
Strings are the most versatile, serializable type which can be transmitted from clients. Because of their versatility, several custom string formatters are supported, by default, in Feathers CLI-generated applications. Additional formats can be manually enabled.
date-time 
Type.String({ format: 'date-time' })Validates against the date-time described in RFC3339/ISO8601, which is the following format:
YYYY-MM-DDTHH:MM:SS.SSS+HH:MM
2022-11-30T11:21:44.000-08:00The sections of this format are described as follows:
- full-date: YYYY-MM-DD
- partial-time: HH:MM:SS.SSS(where.SSSrepresents optional milliseconds)
- time-offset: +HH:MM(where+can be-and which value represents UTC offset or "time zone") required
time 
Type.String({ format: 'time' })Validates against the following format:
HH:MM:SS.SSS+HH:MM
11:21:44.000-08:00The sections of this format are described as follows:
- partial-time: HH:MM:SS.SSS(where.SSSrepresents optional milliseconds)
- time-offset: +HH:MM(where+can be-and which value represents UTC offset or "time zone") optional
date 
Type.String({ format: 'date' })Validates against the full date described in RFC3339/ISO8601, which is the following format:
YYYY-MM-DD
2022-11-30email 
Type.String({ format: 'email' })Validates email addresses against the format specified by RFC 1034.
hostname 
Type.String({ format: 'hostname' })Validates hostnames against the format specified by RFC 1034.
ipv4 
Type.String({ format: 'ipv4' })Validates an IPV4-formatted IP Address.
0.0.0.0 to 255.255.255.255ipv6 
Type.String({ format: 'ipv6' })Validates an IPV6-formatted IP Address.
uri 
Type.String({ format: 'uri' })Validates a full URI.
uri-reference 
Type.String({ format: 'uri-reference' })uuid 
Type.String({ format: 'uuid' })Validates a Universally Unique Identifier according to rfc4122.
uri-template 
Type.String({ format: 'uri-template' })Validates a URI Template according to rfc6570.
json-pointer 
Type.String({ format: 'json-pointer' })Validates a JSON Pointer, according to RFC6901.
relative-json-pointer 
Type.String({ format: 'relative-json-pointer' })Validates a Relative JSON Pointer, according to this draft.
regex 
Type.String({ format: 'regex' })Tests whether a string is a valid regular expression by passing it to RegExp constructor.
Additional Formats 
The ajv-formats package bundled with CLI-generated apps includes additional utilities, listed below, which can be manually enabled by modifying the array of formats in src/schema/validators.ts. The additional formats are highlighted in this code example:
const formats: FormatsPluginOptions = [
  'date-time',
  'time',
  'date',
  'email',
  'hostname',
  'ipv4',
  'ipv6',
  'uri',
  'uri-reference',
  'uuid',
  'uri-template',
  'json-pointer',
  'relative-json-pointer',
  'regex',
  'iso-time',
  'iso-date-time',
  'duration',
  'byte',
  'int32',
  'int64',
  'float',
  'double',
  'password',
  'binary',
]Be aware that there is also an ajv-formats-draft2019 package which can be manually installed. The package allows use of several international formats for urls, domains, and emails. The formats are included in JSON Schema draft-07.
iso-time 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'iso-time' })Validates against UTC-based time format:
HH:MM:SS.SSSZ
11:21:44.000Z
HH:MM:SSZ
11:21:44ZThe sections of this format are described as follows:
- partial-time: HH:MM:SS.SSS(where.SSSrepresents optional milliseconds)
- Z: Z(where Z represents UTC time zone, or time offset 00:00)
iso-date-time 
Type.String({ format: 'iso-date-time' })Validates against the date-time described in RFC3339/ISO8601, which is the following format:
YYYY-MM-DDTHH:MM:SS.SSSZ
2022-11-30T11:21:44.000Z
YYYY-MM-DDTHH:MM:SSZ
2022-11-30T11:21:44ZThe sections of this format are described as follows:
- full-date: YYYY-MM-DD
- partial-time: HH:MM:SS.SSS(where.SSSrepresents optional milliseconds)
- Z: Z(where Z represents UTC time zone, or time offset 00:00)
Duration 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'duration' })A duration string representing a period of time, as specified in rfc3339 appendix-A undder the "Durations" heading. Here's an excerpt of the spec.
Durations:
dur-second        = 1*DIGIT "S"
dur-minute        = 1*DIGIT "M" [dur-second]
dur-hour          = 1*DIGIT "H" [dur-minute]
dur-time          = "T" (dur-hour / dur-minute / dur-second)
dur-day           = 1*DIGIT "D"
dur-week          = 1*DIGIT "W"
dur-month         = 1*DIGIT "M" [dur-day]
dur-year          = 1*DIGIT "Y" [dur-month]
dur-date          = (dur-day / dur-month / dur-year) [dur-time]
duration          = "P" (dur-date / dur-time / dur-week)Byte 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'byte' })Validates base64-encoded data according to the openApi 3.0.0 specification.
int32 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'int32' })Validates signed (+/-), 32-bit integers according to the openApi 3.0.0 specification.
int64 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'int64' })Validates signed (+/-), 64-bit integers according to the openApi 3.0.0 specification.
float 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'float' })Validates floats according to the openApi 3.0.0 specification.
double 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'double' })Validates doubles according to the openApi 3.0.0 specification.
password 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'password' })Validates passwords according to the openApi 3.0.0 specification.
binary 
Must be manually enabled. See Additional Formats.
Type.String({ format: 'binary' })Validates a binary string according to the openApi 3.0.0 specification.
Number 
Creates a number schema and type.
const T = Type.Number()type T = numberconst T = {
  type: 'number'
}Integer 
Creates a number schema and type. The number has to be an integer (not a float).
const T = Type.Integer()type T = numberconst T = {
  type: 'integer'
}Boolean 
Creates a boolean schema and type.
const T = Type.Boolean()type T = booleanconst T = {
  type: 'boolean'
}Null 
Creates a schema and type only allowing null.
const T = Type.Null()type T = nullconst T = {
  type: 'null'
}Literal 
Creates a schema and type that must match the provided value.
const T = Type.Literal(42)type T = 42const T = {
  const: 42,
  type: 'number'
}Object & Array Types 
These utilities creates schemas and types for objects and arrays.
RegEx 
Creates a string schema that validates against a regular expression object. The TypeScript type will be string.
const T = Type.RegEx(/foo/)type T = stringconst T = {
  type: 'string',
  pattern: 'foo'
}Array 
Creates an array of the provided type. You can use any of the utility types to specify what can go in the array, even complex types using union and intersect.
const T = Type.Array(Type.Number())type T = number[]const T = {
  type: 'array',
  items: {
    type: 'number'
  }
}Object 
Creates an object schema where all properties are required by default. You can use the Type.Optional utility to mark a key as optional.
const T = Type.Object({
  x: Type.Number(),
  y: Type.Number()
})type T = {
  x: number,
  y: number
}const T = {
  type: 'object',
  properties: {
    x: {
      type: 'number'
    },
    y: {
      type: 'number'
    }
  },
  required: ['x', 'y']
}Tuple 
Creates an array type with exactly two items matching the specified types.
const T = Type.Tuple([Type.Number(), Type.Number()])type T = [number, number]const T = {
  type: 'array',
  items: [{ type: 'number' }, { type: 'number' }],
  additionalItems: false,
  minItems: 2,
  maxItems: 2
}StringEnum 
StringEnum is a standalone utility to for specifying an array of allowed string values on a property. It is directly exported from @feathersjs/typebox:
// import the module, first
import { StringEnum } from '@feathersjs/typebox'
const T = StringEnum(['crow', 'dove', 'eagle'])
// Add additional options
const T = StringEnum(['crow', 'dove', 'eagle'], {
    default: 'crow'
})To obtain the TypeScript type, use the Static utility:
import { Static } from '@feathersjs/typebox'
type T = Static<typeof T>const T = {
  enum: ['crow', 'dove', 'eagle']
}Enum 
tip
For string values, use StringEnum.
enum Foo {
  A,
  B,
}
const T = Type.Enum(Foo)enum Foo {
  A,
  B,
}
type T = Fooconst T = {
  anyOf: [
    { type: 'number', const: 0 },
    { type: 'number', const: 1 }
  ]
}Utility Types 
The utility types create types which are derived from other types.
KeyOf 
Creates a schema for a string that can be any of the keys of a provided Type.Object. It's similar to TypeScript's KeyOf operator.
const T = Type.KeyOf(
  Type.Object({
    x: Type.Number(),
    y: Type.Number()
  })
)type T = keyof {
  x: number,
  y: number,
}const T = {
  anyOf: [
    { type: 'string', const: 'x' },
    { type: 'string', const: 'y' }
  ]
}Union 
Creates a type which can be one of the types in the provided array. It's the equivalent to using | to form a TypeScript Union.
const T = Type.Union([Type.String(), Type.Number()])type T = string | numberconst T = {
  anyOf: [{ type: 'string' }, { type: 'number' }]
}Intersect 
Creates an object type by combining two or more other object types.
const T = Type.Intersect([
  Type.Object({
    x: Type.Number()
  }),
  Type.Object({
    y: Type.Number()
  })
])type T = { x: number } & { y: number }const T = {
  type: 'object',
  properties: {
    x: { type: 'number' },
    y: { type: 'number' }
  },
  required: ['x', 'y']
}Never 
Creates a type that will never validate if the attribute is present. This is useful if you are allowing additionalProperties but need to prevent using specific keys.
const T = Type.Never()type T = neverconst T = {
  allOf: [
    { type: 'boolean', const: false },
    { type: 'boolean', const: true }
  ]
}Record 
Creates the JSON Schema equivalent of TypeScript's Record utility type.
const T = Type.Record(Type.String(), Type.Number())type T = Record<string, number>const T = {
  type: 'object',
  patternProperties: {
    '^.*$': {
      type: 'number'
    }
  }
}Partial 
Creates a schema for an object where all keys are optional. It's the opposite of Required, and the JSON Schema equivalent of TypeScript's Partial utility type.
const T = Type.Partial(
  Type.Object({
    x: Type.Number(),
    y: Type.Number()
  })
)type T = Partial<{
  x: number,
  y: number
}>const T = {
  type: 'object',
  properties: {
    x: { type: 'number' },
    y: { type: 'number' }
  }
}Required 
Creates a schema for an object where all keys are required, even ignoring if keys are marked with Type.Optional. It's the opposite of Partial, and the JSON Schema equivalent of TypeScript's Required utility type.
const T = Type.Required(
  Type.Object({
    x: Type.Optional(Type.Number()),
    y: Type.Optional(Type.Number())
  })
)type T = Required<{
  x?: number,
  y?: number
}>const T = {
  type: 'object',
  properties: {
    x: { type: 'number' },
    y: { type: 'number' }
  },
  required: ['x', 'y']
}Pick 
Forms a new object containing only the array of keys provided in the second argument. It's the JSON Schema equivalent of TypeScript's Pick utility type.
const T = Type.Pick(
  Type.Object({
    x: Type.Number(),
    y: Type.Number()
  }),
  ['x']
)type T = Pick<
  {
    x: number,
    y: number
  },
  'x'
>const T = {
  type: 'object',
  properties: {
    x: { type: 'number' }
  },
  required: ['x']
}Omit 
Forms a new object containing all keys except those provided in the second argument. It's the JSON Schema equivalent of TypeScript's Omit utility type.
const T = Type.Omit(
  Type.Object({
    x: Type.Number(),
    y: Type.Number()
  }),
  ['x']
)type T = Omit<
  {
    x: number,
    y: number
  },
  'x'
>const T = {
  type: 'object',
  properties: {
    y: { type: 'number' }
  },
  required: ['y']
}Modifiers 
TypeBox provides modifiers that can be applied to an objects properties. This allows for optional and readonly to be applied to that property. The following table illustrates how they map between TypeScript and JSON Schema.
Optional 
Allows marking a key in Type.Object as optional.
const T = Type.Object({
  name: Type.Optional(Type.String())
})type T = {
  name?: string
}const T = {
  type: 'object',
  properties: {
    name: {
      type: 'string'
    }
  }
}Readonly 
Allows marking a key in Type.Object as readonly. It's the equivalent of TypeScript's Readonly utility type.
const T = Type.Object({
  name: Type.Readonly(Type.String())
})type T = {
  readonly name: string
}const T = {
  type: 'object',
  properties: {
    name: {
      type: 'string'
    }
  },
  required: ['name']
}ReadonlyOptional 
Allows marking a key in Type.Object as both readonly and optional.
const T = Type.Object({
  name: Type.ReadonlyOptional(Type.String())
})type T = {
  readonly name?: string
}const T = {
  type: 'object',
  properties: {
    name: {
      type: 'string'
    }
  }
}Options by Type 
You can pass additional JSON schema options on the last argument of any given type. The JSON Schema specification describes options for each data type. Descriptions from the specification are copied here for easy reference.
For Numbers 
Number types support the following options, which can be used simultaneously.
multipleOf 
The value of "multipleOf" MUST be a number, strictly greater than 0. Values are valid only if division by this keyword's value results in an integer.
const T = Type.Number({ multipleOf: 2 })maximum 
The value of "maximum" MUST be a number, representing an inclusive upper limit for a numeric instance. If the instance is a number, then this keyword validates only if the instance is less than or exactly equal to "maximum".
const T = Type.Number({ maximum: 20 })exclusiveMaximum 
The value of "exclusiveMaximum" MUST be a number, representing an exclusive upper limit for a numeric instance. If the instance is a number, then the instance is valid only if it has a value strictly less than (not equal to) "exclusiveMaximum".
const T = Type.Number({ exclusiveMaximum: 20 })minimum 
The value of "minimum" MUST be a number, representing an inclusive lower limit for a numeric instance. If the instance is a number, then this keyword validates only if the instance is greater than or exactly equal to "minimum".
const T = Type.Number({ minimum: 20 })exclusiveMinimum 
The value of "exclusiveMinimum" MUST be a number, representing an exclusive lower limit for a numeric instance. If the instance is a number, then the instance is valid only if it has a value strictly greater than (not equal to) "exclusiveMinimum".
const T = Type.Number({ exclusiveMinimum: 20 })For Strings 
String types support the following options, which can be used simultaneously.
maxLength 
The value of this keyword MUST be a non-negative integer. A string instance is valid against this keyword if its length is less than, or equal to, the value of this keyword. The length of a string instance is defined as the number of its characters as defined by RFC 8259 [RFC8259].
minLength 
The value of this keyword MUST be a non-negative integer. A string instance is valid against this keyword if its length is greater than, or equal to, the value of this keyword. The length of a string instance is defined as the number of its characters as defined by RFC 8259 [RFC8259]. Omitting this keyword has the same behavior as a value of 0.
pattern 
Use Type.Regex, instead of this option.
With AJV Formats 
There are four custom options which are only available for certain formats when using the ajv-formats package:
The above-listed options are only available when using the following string formats.
formatMinimum 
Allows defining minimum constraints when the format keyword defines ordering (using the compare function in format definition). Available when using ajv-formats.
The following example validates that the provided date is on or after November 13, 2022.
Type.String({ format: 'date', formatMinimum: '2022-11-13' })formatMaximum 
Allows defining maximum constraints when the format keyword defines ordering (using the compare function in format definition). Available when using ajv-formats.
The following example validates that the provided date is on or before November 13, 2022.
Type.String({ format: 'date', formatMaximum: '2022-11-13' })formatExclusiveMinimum 
Allows defining exclusive minimum constraints when the format keyword defines ordering (using the compare function in format definition). Available when using ajv-formats.
The following example validates that the provided date is after (and not on) November 13, 2022.
Type.String({ format: 'date', formatExclusiveMinimum: '2022-11-13' })formatExclusiveMaximum 
Allows defining exclusive maximum constraints when the format keyword defines ordering (using the compare function in format definition). Available when using ajv-formats.
The following example validates that the provided date is before (and not on) November 13, 2022.
Type.String({ format: 'date', formatExclusiveMaximum: '2022-11-13' })For Arrays 
Array types support the following options, which can be used simultaneously.
maxItems 
The value of this keyword MUST be a non-negative integer. An array instance is valid against "maxItems" if its size is less than, or equal to, the value of this keyword.
minItems 
The value of this keyword MUST be a non-negative integer. An array instance is valid against "minItems" if its size is greater than, or equal to, the value of this keyword. Omitting this keyword has the same behavior as a value of 0.
uniqueItems 
The value of this keyword MUST be a boolean. If this keyword has boolean value false, the instance validates successfully. If it has boolean value true, the instance validates successfully if all of its elements are unique. Omitting this keyword has the same behavior as a value of false.
maxContains 
The value of this keyword MUST be a non-negative integer.
If "contains" is not present within the same schema object, then this keyword has no effect.
An instance array is valid against "maxContains" in two ways, depending on the form of the annotation result of an adjacent "contains" [json-schema] keyword. The first way is if the annotation result is an array and the length of that array is less than or equal to the "maxContains" value. The second way is if the annotation result is a boolean "true" and the instance array length is less than or equal to the "maxContains" value.
minContains 
The value of this keyword MUST be a non-negative integer.
If "contains" is not present within the same schema object, then this keyword has no effect.
An instance array is valid against "minContains" in two ways, depending on the form of the annotation result of an adjacent "contains" [json-schema] keyword. The first way is if the annotation result is an array and the length of that array is greater than or equal to the "minContains" value. The second way is if the annotation result is a boolean "true" and the instance array length is greater than or equal to the "minContains" value.
A value of 0 is allowed, but is only useful for setting a range of occurrences from 0 to the value of "maxContains". A value of 0 causes "minContains" and "contains" to always pass validation (but validation can still fail against a "maxContains" keyword).
Omitting this keyword has the same behavior as a value of 1.
For Objects 
Array types support the following options, which can be used simultaneously.
additionalProperties 
Specifies if keys other than the ones specified in the schema are allowed to be present in the object.
maxProperties 
The value of this keyword MUST be a non-negative integer. An object instance is valid against "maxProperties" if its number of properties is less than, or equal to, the value of this keyword.
minProperties 
The value of this keyword MUST be a non-negative integer. An object instance is valid against "minProperties" if its number of properties is greater than, or equal to, the value of this keyword. Omitting this keyword has the same behavior as a value of 0.
required 
All TypeBox types are required unless you wrap them in Type.Optional, so you don't need to use this option, manually.
dependentRequired 
The value of this keyword MUST be an object. Properties in this object, if any, MUST be arrays. Elements in each array, if any, MUST be strings, and MUST be unique.
This keyword specifies properties that are required if a specific other property is present. Their requirement is dependent on the presence of the other property.
Validation succeeds if, for each name that appears in both the instance and as a name within this keyword's value, every item in the corresponding array is also the name of a property in the instance.
Omitting this keyword has the same behavior as an empty object.
Extended 
In addition to JSON schema types, TypeBox provides several extended types that allow for the composition of function and constructor types. These additional types are not valid JSON Schema and will not validate using typical JSON Schema validation. However, these types can be used to frame JSON schema and describe callable interfaces that may receive JSON validated data. Since these are nonstandard types, most applications will not need them. Consider using the Standard Types, instead, as using these types may make it difficult to upgrade your application in the future.
Extended Configuration 
Utilities in this section require updating src/schemas/validators.ts to the Extended Ajv Configuration, as shown here:
import { TypeGuard } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'
import addFormats from 'ajv-formats'
import type { Options } from 'ajv'
import Ajv from 'ajv'
function schemaOf(schemaOf: string, value: unknown, schema: unknown) {
  switch (schemaOf) {
    case 'Constructor':
      return TypeGuard.IsConstructor(schema) && Value.Check(schema, value) // not supported
    case 'Function':
      return TypeGuard.IsFunction(schema) && Value.Check(schema, value) // not supported
    case 'Date':
      return TypeGuard.IsDate(schema) && Value.Check(schema, value)
    case 'Promise':
      return TypeGuard.IsPromise(schema) && Value.Check(schema, value) // not supported
    case 'Uint8Array':
      return TypeGuard.IsUint8Array(schema) && Value.Check(schema, value)
    case 'Undefined':
      return TypeGuard.IsUndefined(schema) && Value.Check(schema, value) // not supported
    case 'Void':
      return TypeGuard.IsVoid(schema) && Value.Check(schema, value)
    default:
      return false
  }
}
export function createAjv(options: Options = {}) {
  return addFormats(new Ajv(options), [
    'date-time',
    'time',
    'date',
    'email',
    'hostname',
    'ipv4',
    'ipv6',
    'uri',
    'uri-reference',
    'uuid',
    'uri-template',
    'json-pointer',
    'relative-json-pointer',
    'regex',
  ])
  .addKeyword({ type: 'object', keyword: 'instanceOf', validate: schemaOf })
  .addKeyword({ type: 'null', keyword: 'typeOf', validate: schemaOf })
  .addKeyword('exclusiveMinimumTimestamp')
  .addKeyword('exclusiveMaximumTimestamp')
  .addKeyword('minimumTimestamp')
  .addKeyword('maximumTimestamp')
  .addKeyword('minByteLength')
  .addKeyword('maxByteLength')
}
export const dataValidator: Ajv = createAjv({})
export const queryValidator: Ajv = createAjv({ coerceTypes: true })If you see an error stating Error: strict mode: unknown keyword: "instanceOf", it's likely because you need to extend your configuration, as shown above.
Constructor 
Verifies that the value is a constructor with typed arguments and return value. Requires Extended Ajv Configuration.
const T = Type.Constructor([Type.String(), Type.Number()], Type.Boolean())type T = new (
  arg0: string,
  arg1: number,
) => booleanconst T = {
  type: 'constructor',
  parameters: [
    { type: 'string' },
    { type: 'number' },
  ],
  return {
    type: 'boolean',
  },
}Function 
Verifies that the value is a function with typed arguments and return value. Requires Extended Ajv Configuration.
const T = Type.Function([Type.String(), Type.Number()], Type.Boolean())type T = ({
  arg0: string,
  arg1: number
}) => booleanconst T = {
  type: 'function',
  parameters: [
    { type: 'string' },
    { type: 'number' },
  ],
  return {
    type: 'boolean',
  },
}Promise 
Verifies that the value is an instanceof Promise which resolves to the provided type. Requires Extended Ajv Configuration.
const T = Type.Promise(Type.String())type T = Promise<string>const T = {
  type: 'promise',
  item: { type: 'string' }
}Uint8Array 
Verifies that the value is an instanceof Uint8Array. Requires Extended Ajv Configuration.
const T = Type.Uint8Array()type T = Uint8Arrayconst T = {
  type: 'object',
  instanceOf: 'Uint8Array'
}Date 
Verifies that the value is an instanceof Date. This is likely not the validator to use for storing dates in a database. See Validating Dates. Requires Extended Ajv Configuration.
const T = Type.Date()type T = Dateconst T = {
  type: 'object',
  instanceOf: 'Date'
}Undefined 
Verifies that the value is undefined. Requires Extended Ajv Configuration.
const T = Type.Undefined()type T = undefinedconst T = {
  type: 'object',
  specialized: 'Undefined'
}Symbol 
Verifies that the value is of type Symbol. Requires Extended Ajv Configuration.
const T = Type.Symbol()type T = symbolconst T = {
  type: 'null',
  typeOf: 'Symbol'
}BigInt 
Verifies that the value is of type BigInt. Requires Extended Ajv Configuration.
const T = Type.BigInt()type T = bigintconst T = {
  type: 'null',
  typeOf: 'BigInt'
}Void 
Verifies that the value is null. Requires Extended Ajv Configuration.
const T = Type.Void()type T = voidconst T = {
  type: 'null'
}Reference 
Use Type.Ref(...) to create referenced types. The target type must specify an $id.
const T = Type.String({ $id: 'T' })
const R = Type.Ref(T)For a more detailed example see the result and data schema section.