Skip to content

Commit

Permalink
release 0.5
Browse files Browse the repository at this point in the history
  • Loading branch information
vitalics committed Jan 17, 2024
1 parent 7c31815 commit d697394
Show file tree
Hide file tree
Showing 9 changed files with 588 additions and 110 deletions.
112 changes: 112 additions & 0 deletions .changeset/pink-dots-prove.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
---
"ajv-ts": minor
---

Minor release `0.5` is Out!

## New Features

### not, exclude

Now you can mark your schema with `not` keyword.

Here is a 2 differences between `not` and `exclude`.

- `not` method wrap given schema with `not`
- `exclude(schema)` - add `not` keyword for incoming `schema` argument

Example:

```ts
import s from 'ajv-ts'

// not
const notAString = s.string().not() // or s.not(s.string())

notAString.valid('random string') // false, this is a string
notAString.valid(123) // true

// exclude
const notJohn = s.string().exclude(s.const('John'))

notJohn.valid('random string') // true
notJohn.valid('John') // false, this is John

// advanced usage

const str = s.string<'John' | 'Mary'>().exclude(s.const('John'))
s.infer<typeof str> // 'Mary'
```

### keyof

New function that can be used in a root. Same as `keyof T` in Typescript.

Example:

```ts
import s from 'ajv-ts'

const schema = s.keyof(s.object({
key1: s.string(),
key2: s.object({})
}))

type Result = s.infer<typeof schema> // 'key1' | 'key2'

```

### Never

Same as `never` type in Typescript. JSON-schema equivalent is `{not: {}}`.

## Fixes

- `s.number()` - now generic!
- `s.boolean()` - now generic!

### Array

#### Optional schema definition

function can be called without schema definition

```ts
import s from 'ajv-ts'
// before 0.5
s.array() // error

// 0.5 and later
s.array() // OK, deinition is not required anymore!
```

#### minContains/maxContains

Improve typescript generics usage. Now you cannot set float or negative values.

Example:

```ts
import s from 'ajv-ts'

// Before 0.5
s.array(s.number()).minContains(-1) // Typescript was silent

// After 0.5
s.array(s.number()).minContains(-1) // Typescript error: `Argument of type 'number' is not assignable to parameter of type '[never, 'TypeError: "minContains" should be positive integer', "Received: '-1'"]'.`
```

## JS Doc updates

Update and add JS Doc for:

- `nullable` - update
- `array` - update
- `validate` - update
- `parse` - update
- `number().const()` - update
- `array().contains()` - add
- `const()` - add
- `any()` - update
- `unknown` - update
- `create` - update
107 changes: 92 additions & 15 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,5 +1,57 @@
# ajv-ts

## Table of Contents

- [ajv-ts](#ajv-ts)
- [Table of Contents](#table-of-contents)
- [Zod unsupported APIs/differences](#zod-unsupported-apisdifferences)
- [Installation](#installation)
- [Basic usage](#basic-usage)
- [Primitives](#primitives)
- [Constant values(literals)](#constant-valuesliterals)
- [String](#string)
- [Numbers](#numbers)
- [BigInts](#bigints)
- [NaNs](#nans)
- [Dates](#dates)
- [Enums](#enums)
- [Autocompletion](#autocompletion)
- [Native enums](#native-enums)
- [Optionals](#optionals)
- [Nullables](#nullables)
- [Objects](#objects)
- [`.keyof`](#keyof)
- [`.extend`](#extend)
- [`.merge`](#merge)
- [`.pick`/`.omit`](#pickomit)
- [`.partial`](#partial)
- [`.required`](#required)
- [`.requiredFor`](#requiredfor)
- [`.partialFor`](#partialfor)
- [`.passthrough`](#passthrough)
- [`.strict`](#strict)
- [`.dependentRequired`](#dependentrequired)
- [`.rest`](#rest)
- [Arrays](#arrays)
- [`.element`](#element)
- [`.nonempty`](#nonempty)
- [`.min`/`.max`/`.length`/`.minLength`/`.maxLength`](#minmaxlengthminlengthmaxlength)
- [`.unique`](#unique)
- [`.contains`/`.minContains`](#containsmincontains)
- [Tuples](#tuples)
- [unions/or](#unionsor)
- [Intersections/and](#intersectionsand)
- [Set](#set)
- [Map](#map)
- [`any`/`unknown`](#anyunknown)
- [`never`](#never)
- [`not`/`exclude`](#notexclude)
- [Custom Ajv instance](#custom-ajv-instance)
- [`custom` shema definition](#custom-shema-definition)
- [Transformations](#transformations)
- [Preprocess](#preprocess)
- [Postprocess](#postprocess)

JSON schema builder like in ZOD-like API

> TypeScript schema validation with static type inference!
Expand All @@ -15,7 +67,7 @@ We inspired API from `zod`. So you just can reimport you api and that's it!

## Zod unsupported APIs/differences

1. `s.date`, `s.symbol`, `s.void`, `s.void`, `s.never`, `s.bigint`, `s.function` does not supported. Since JSON-schema doesn't define `Date`, `Symbol`, `void`, `never`, `function`, `Set`, `Map` as separate type. For strings you can use `s.string().format('date-time')` or other JSON-string format compatibility: https://json-schema.org/understanding-json-schema/reference/string.html
1. `s.date`, `s.symbol`, `s.void`, `s.void`, `s.bigint`, `s.function` does not supported. Since JSON-schema doesn't define `Date`, `Symbol`, `void`, `function`, `Set`, `Map` as separate type. For strings you can use `s.string().format('date-time')` or other JSON-string format compatibility: https://json-schema.org/understanding-json-schema/reference/string.html
2. `s.null` === `s.undefined` - same types, but helps typescript with autocompletion
3. `z.enum` and `z.nativeEnum` it's a same as `s.enum`. We make enums fully compatible, it can be array of strings or structure defined with `enum` keyword in typescript
4. Exporting `s` isntead of `z`, since `s` - is a shorthand for `schema`
Expand Down Expand Up @@ -636,21 +688,15 @@ const result = variadicTuple.parse(["hello", 1, 2, 3]);

includes a built-in s.union method for composing "OR" types.

This function accepts array of schemas by spread argument or array.
This function accepts array of schemas by spread argument.

```ts
const stringOrNumber = s.union([s.string(), s.number()]);
const stringOrNumber = s.union(s.string(), s.number());

stringOrNumber.parse("foo"); // passes
stringOrNumber.parse(14); // passes
```

Or it's invariant:

```ts
s.union(s.string(), s.number()) // string | number
```

Or it's invariant - `or` function:

```ts
Expand All @@ -659,7 +705,7 @@ s.number().or(s.string()) // number | string

## Intersections/and

Intersections are useful for creating "logical AND" types. This is useful for intersecting two object types.
Intersections are "logical AND" types. This is useful for intersecting two object types.

```ts
const Person = s.object({
Expand All @@ -672,9 +718,6 @@ const Employee = s.object({

const EmployedPerson = s.intersection(Person, Employee);

// same as
const EmployedPerson = s.intersection([Person, Employee]);

// equivalent to:
const EmployedPerson = Person.and(Employee);

Expand All @@ -685,8 +728,8 @@ const EmployedPerson = and(Person, Employee);
Though in many cases, it is recommended to use `A.merge(B)` to merge two objects. The `.merge` method returns a new Object instance, whereas `A.and(B)` returns a less useful Intersection instance that lacks common object methods like `pick` and `omit`.

```ts
const a = s.union([s.number(), s.string()]);
const b = s.union([s.number(), s.boolean()]);
const a = s.union(s.number(), s.string());
const b = s.union(s.number(), s.boolean());
const c = s.intersection(a, b);

type c = s.infer<typeof c>; // => number
Expand All @@ -704,6 +747,40 @@ Not supported

Any and unknown defines `{}` (empty object) as JSON-schema. very useful if you need to create something specific

## `never`

Never defines using `{not: {}}` (empty not). Any given json schema will be fails.

## `not`/`exclude`

Here is a 2 differences between `not` and `exclude`.

- `not` method wrap given schema with `not`
- `exclude(schema)` - add `not` keyword for incoming `schema` argument

Example:

```ts
import s from 'ajv-ts'

// not
const notAString = s.string().not() // or s.not(s.string())

notAString.valid('random string') // false, this is a string
notAString.valid(123) // true

// exclude
const notJohn = s.string().exclude(s.const('John'))

notJohn.valid('random string') // true
notJohn.valid('John') // false, this is John

// advanced usage

const str = s.string<'John' | 'Mary'>().exclude(s.const('John'))
s.infer<typeof str> // 'Mary'
```

## Custom Ajv instance

If you need to create a custom AJV Instance, you can use `create` or `new` function.
Expand Down
Loading

0 comments on commit d697394

Please sign in to comment.