Schemas
| Juniper class | JSON Schema | TypeScript |
|---|---|---|
ArraySchema | type: 'array' | unknown[] |
BooleanSchema | type: 'boolean' | boolean |
CustomSchema | Whatever is provided | Whatever is provided |
EnumSchema | enum: [] | Union of the provided literals |
MergeSchema | None (compositional) | unknown, then | or & as appropriate |
NeverSchema | not: {} | never |
NullSchema | type: 'null' | null |
NumberSchema | type: 'number' or type: 'integer' | number |
ObjectSchema | type: 'object' | {} |
StringSchema | type: 'string' | string |
TupleSchema | type: 'array' | [unknown] |
- There is no
anyschema. UseMergeSchemaforunknown. Ifanyis truly required, useCustomSchema, whose default output is an always-valid empty schema. - In the tables below, Constructor parameter means the keyword can be passed to the constructor as well as set with its method. Can be unset means the method accepts
undefinedto remove it. Changes types means it narrows the inferred TypeScript type.
Generic schema methods
Available on every schema, except where the result would be nonsensical (for example, EnumSchema can't be nullable). All methods return a new instance.
| Method | Constructor parameter | Can be unset | Changes types |
|---|---|---|---|
title | ✅ | ✅ | ❌ |
description | ✅ | ✅ | ❌ |
default | ✅ | ✅ | ❌ |
deprecated | ✅ | ✅ | ❌ |
example(s) | ❌ | ❌ | ❌ |
readOnly | ✅ | ✅ | ❌ |
writeOnly | ✅ | ✅ | ❌ |
allOf | ❌ | ❌ | ✅ |
anyOf | ❌ | ❌ | ✅ |
oneOf | ❌ | ❌ | ✅ |
not | ❌ | ❌ | ✅ |
if then else | ❌ | ❌ | ✅ |
nullable | ❌ | ❌ | ✅ |
not(schema) rejects everything schema accepts, including null when schema is nullable. To make a nullable schema non-nullable, pass nullSchema():
import { nullSchema, stringSchema } from 'juniper';
// string, emitted as { type: 'string' }
const name = stringSchema().nullable().not(nullSchema());By contrast, .not(stringSchema().nullable()) rejects every string as well as null, so nothing passes.
ArraySchema
Represents type: 'array'. TypeScript type: unknown[].
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
items | ✅ | ❌ | ✅ | ✅ |
maxItems | ✅ | ✅ | ❌ | ✅ |
minItems | ✅ | ✅ | ✅ | ✅ |
uniqueItems | ✅ | ✅ | ❌ | ✅ |
contains | ❌ | ❌ | ✅ | ❌ |
maxContains | ✅ | ✅ | ❌ | ❌ |
minContains | ✅ | ✅ | ❌ | ❌ |
(prepend)prefixItem | ❌ | ❌ | ✅ | ❌ |
minItems up to 3 makes those items required in the type, so an empty array is rejected where the schema rejects it:
import { arraySchema, stringSchema, type SchemaType } from 'juniper';
const tags = arraySchema(stringSchema()).minItems(1);
type Tags = SchemaType<typeof tags>;Larger values, or a number variable, leave the type as an array. To build a value from an array of unknown length, narrow it first, as a length check alone does not:
const isNonEmpty = <T>(array: T[]): array is [T, ...T[]] => array.length > 0;EnumSchema
Represents enum: []. TypeScript type: union of provided literals.
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
enum(s) | ✅ | ❌ | ✅ | ✅ |
NumberSchema
Represents type: 'number' or type: 'integer'. TypeScript type: number.
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
type | ✅ | ✅ | ❌ | ✅ |
multipleOf | ✅ | ❌ | ❌ | ✅ |
maximum | ✅ | ✅ | ❌ | ✅ |
exclusiveMaximum | ✅ | ✅ | ❌ | ✅ |
minimum | ✅ | ✅ | ❌ | ✅ |
exclusiveMinimum | ✅ | ✅ | ❌ | ✅ |
ObjectSchema
Represents type: 'object'. TypeScript type: {}.
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
properties | ✅ | ✅ | ✅ | ✅ |
maxProperties | ✅ | ✅ | ❌ | ✅ |
minProperties | ✅ | ✅ | ❌ | ✅ |
required | ✅ | ✅ | ✅ | ✅ |
additionalProperties | ✅ | ✅ | ✅ | ✅ |
patternProperties | ❌ | ✅ | ✅ | ❌ |
dependentRequired | ❌ | ❌ | ✅ | ✅ |
dependentSchemas | ❌ | ❌ | ✅ | ✅ |
unevaluatedProperties | ✅ | ❌ | ❌ | ❌ |
Note on additionalProperties: JSON Schema interprets omitting additionalProperties as additionalProperties: true. The emitted TypeScript type includes the index signature only when additionalProperties is explicitly set to true:
import { objectSchema, type SchemaType } from 'juniper';
const empty = objectSchema();
type EmptyObject = SchemaType<typeof empty>;
const indexed = empty.additionalProperties(true);
type IndexedObject = SchemaType<typeof indexed>;Note on patternProperties: The key is a regular expression pattern and cannot be interpreted directly as a TypeScript string type. Wrap the key with the PatternProperties helper type:
import { numberSchema, objectSchema, type PatternProperties, type SchemaType } from 'juniper';
const startsOrEndsWith = objectSchema()
.patternProperties(
'^abc' as PatternProperties<`abc${string}`>,
true
)
.patternProperties(
'xyz$' as PatternProperties<`${string}xyz`>,
numberSchema()
);
type Output = SchemaType<typeof startsOrEndsWith>;Discriminated unions: oneOf(schemas, { discriminator: 'kind' }) checks that every branch requires kind as a single, unique string value, and emits OpenAPI's discriminator keyword. See Discriminated unions.
To derive variants of an object schema with pick, omit, partial, required and extend, see Deriving object schemas.
StringSchema
Represents type: 'string'. TypeScript type: string.
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
format | ✅ | ✅ | ❌ | ✅ |
maxLength | ✅ | ✅ | ❌ | ✅ |
minLength | ✅ | ✅ | ❌ | ✅ |
pattern | ✅ | ❌ | ❌ | ✅ |
startsWith | ❌ | ❌ | ✅ | ✅ |
endsWith | ❌ | ❌ | ✅ | ✅ |
contains | ❌ | ❌ | ✅ | ✅ |
contentEncoding | ✅ | ✅ | ❌ | ❌ |
contentMediaType | ✅ | ✅ | ❌ | ❌ |
OpenAPI 3.0 has no contentEncoding or contentMediaType, so they are left out of its output. Use format('byte') (base64) or format('binary') instead.
startsWith, endsWith, and contains are wrappers around the pattern property with special TypeScript handling to narrow the inferred string type (e.g. startsWith('abc') produces `abc${string}`).
format autocompletes the formats defined by JSON Schema and OpenAPI 3.0 (date-time, email, uuid, uri, ..., exported as the KnownFormat type), and accepts any other string as a custom format.
TupleSchema
Represents type: 'array' with strict tuple semantics. TypeScript type: [unknown]. A convenience wrapper around ArraySchema that prevents editing items directly. Every TupleSchema is an ArraySchema.
| Method | Constructor Parameter | Can be Unset | Changes Types | OpenAPI 3.0 |
|---|---|---|---|---|
uniqueItems | ✅ | ✅ | ❌ | ✅ |
contains | ❌ | ❌ | ✅ | ❌ |
maxContains | ✅ | ✅ | ❌ | ❌ |
minContains | ✅ | ✅ | ❌ | ❌ |
(prepend)prefixItem | ❌ | ❌ | ✅ | ❌ |
BooleanSchema
Represents type: 'boolean'. TypeScript type: boolean.
Exposes all generic schema methods. Does not expose not (use EnumSchema to restrict boolean values).
NullSchema
Represents type: 'null'. TypeScript type: null.
Exposes all generic schema methods.
NeverSchema
Represents not: {}. TypeScript type: never.
Exposes all generic schema methods.
MergeSchema
A compositional schema with no inherent type constraint. TypeScript type: unknown initially, narrowed to | or & via anyOf/allOf. Use this for generic unknown types or to combine unrelated schemas.
Exposes all generic schema methods.
CustomSchema
Accepts arbitrary JSON Schema content. TypeScript type is provided via the generic parameter.
import { customSchema } from 'juniper';
const mySchema = customSchema<{ foo: string }>({ foo: { type: 'string' } });Use CustomSchema when integrating with pre-existing JSON Schemas or adopting Juniper incrementally. Its use is discouraged in greenfield code.