Skip to content

Commit 185eb13

Browse files
authored
General Maintenance (#489)
1 parent 3f50917 commit 185eb13

File tree

14 files changed

+543
-850
lines changed

14 files changed

+543
-850
lines changed

example/collections/readme.md

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Collections
2+
3+
This example implements runtime type safe generic `Array`, `Map` and `Set` collection types using TypeBox types as the generic type arguments.

example/experimental/experimental.ts

-109
This file was deleted.

example/experimental/index.ts

+4-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*--------------------------------------------------------------------------
22
3-
@sinclair/typebox/extensions
3+
@sinclair/typebox/experimental
44
55
The MIT License (MIT)
66
@@ -26,4 +26,6 @@ THE SOFTWARE.
2626
2727
---------------------------------------------------------------------------*/
2828

29-
export * from './experimental'
29+
export * from './readonly-object'
30+
export * from './union-enum'
31+
export * from './union-oneof'

example/experimental/readme.md

+44-20
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,54 @@
1-
# ExperimentalTypeBuilder
1+
# Experimental Types
22

3-
An experimental TypeBox type builder with additional custom types.
3+
These examples are a set of experiemental candidate types that may introduced into TypeBox in future.
44

5-
## Overview
5+
## ReadonlyObject
66

7-
The TypeBox TypeBuilder classes are designed to be extended with user defined types. Instances where you may wish to do this are if your application is dependent on custom schematics and/or non-JSON serializable values (an example of which might be a Mongo's `ObjectId` or other such non-serializable value)
7+
Maps an object properties as `readonly`.
88

9-
## Application Type Builder
9+
```typescript
10+
import { ReadonlyObject } from './experimental'
11+
12+
const T = ReadonlyObject(Type.Object({
13+
x: Type.Number()
14+
}))
15+
16+
type T = Static<typeof T> // type T = {
17+
// readonly x: number
18+
// }
19+
```
20+
## UnionEnum
1021
11-
The following shows creating a simple `ApplicationTypeBuilder` with additional types `Nullable` and `StringEnum`. These types are fairly common in OpenAPI implementations.
22+
Creates an `enum` union string schema representation.
1223
1324
```typescript
14-
import { StandardTypeBuilder, Static, TSchema } from '@sinclair/typebox'
15-
16-
export class ApplicationTypeBuilder extends StandardTypeBuilder { // only JSON Schema types
17-
public Nullable<T extends TSchema>(schema: T) {
18-
return this.Unsafe<Static<T> | null>({ ...schema, nullable: true })
19-
}
20-
public StringEnum<T extends string[]>(values: [...T]) {
21-
return this.Unsafe<T[number]>({ type: 'string', enum: values })
22-
}
23-
}
24-
25-
export const Type = new ApplicationTypeBuilder() // re-export!
25+
import { UnionEnum } from './experimental'
26+
27+
28+
const T = UnionEnum(['A', 'B', 'C']) // const T = {
29+
// enum: ['A', 'B', 'C']
30+
// }
31+
32+
type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
33+
2634
```
35+
## UnionOneOf
36+
37+
Creates a `oneOf` union representation.
38+
39+
40+
```typescript
41+
import { UnionOneOf } from './experimental'
42+
43+
44+
const T = UnionOneOf([ // const T = {
45+
Type.Literal('A'), // oneOf: [
46+
Type.Literal('B'), // { const: 'A' },
47+
Type.Literal('C') // { const: 'B' },
48+
]) // { const: 'C' },
49+
// ]
50+
// }
2751

28-
## Experimental Type Builder
52+
type T = Static<typeof T> // type T = 'A' | 'B' | 'C'
2953

30-
The `experimental.ts` file provided with this example shows advanced usage by creating complex types for potential inclusion in the TypeBox library in later revisions. It is offered for reference, experimentation and is open to contributor submission.
54+
```
+68
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
/*--------------------------------------------------------------------------
2+
3+
@sinclair/typebox/experimental
4+
5+
The MIT License (MIT)
6+
7+
Copyright (c) 2017-2023 Haydn Paterson (sinclair) <[email protected]>
8+
9+
Permission is hereby granted, free of charge, to any person obtaining a copy
10+
of this software and associated documentation files (the "Software"), to deal
11+
in the Software without restriction, including without limitation the rights
12+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
13+
copies of the Software, and to permit persons to whom the Software is
14+
furnished to do so, subject to the following conditions:
15+
16+
The above copyright notice and this permission notice shall be included in
17+
all copies or substantial portions of the Software.
18+
19+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
21+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
22+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
23+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
24+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
25+
THE SOFTWARE.
26+
27+
---------------------------------------------------------------------------*/
28+
29+
import * as Types from '@sinclair/typebox'
30+
31+
// -------------------------------------------------------------------------------------
32+
// TReadonlyObject
33+
// -------------------------------------------------------------------------------------
34+
export type TReadonlyArray<T extends Types.TSchema[]> = Types.Assert<{ [K in keyof T]: TReadonlyObject<Types.Assert<T[K], Types.TSchema>> }, Types.TSchema[]>
35+
// prettier-ignore
36+
export type TReadonlyProperties<T extends Types.TProperties> = Types.Evaluate<Types.Assert<{
37+
[K in keyof T]:
38+
T[K] extends Types.TReadonlyOptional<infer U> ? Types.TReadonlyOptional<U> :
39+
T[K] extends Types.TReadonly<infer U> ? Types.TReadonly<U> :
40+
T[K] extends Types.TOptional<infer U> ? Types.TReadonlyOptional<U> :
41+
Types.TReadonly<T[K]>
42+
}, Types.TProperties>>
43+
// prettier-ignore
44+
export type TReadonlyObject<T extends Types.TSchema> =
45+
T extends Types.TIntersect<infer S> ? Types.TIntersect<TReadonlyArray<S>> :
46+
T extends Types.TUnion<infer S> ? Types.TUnion<TReadonlyArray<S>> :
47+
T extends Types.TObject<infer S> ? Types.TObject<TReadonlyProperties<S>> :
48+
Types.TReadonly<T>
49+
50+
/** `[Experimental]` Remaps a Intersect, Union or Object as readonly */
51+
export function ReadonlyObject<T extends Types.TSchema>(schema: T): TReadonlyObject<T> {
52+
function Apply(property: Types.TSchema): any {
53+
// prettier-ignore
54+
switch (property[Types.Modifier]) {
55+
case 'ReadonlyOptional': property[Types.Modifier] = 'ReadonlyOptional'; break
56+
case 'Readonly': property[Types.Modifier] = 'Readonly'; break
57+
case 'Optional': property[Types.Modifier] = 'ReadonlyOptional'; break
58+
default: property[Types.Modifier] = 'Readonly'; break
59+
}
60+
return property
61+
}
62+
// prettier-ignore
63+
return (Types.TypeGuard.TIntersect(schema) || Types.TypeGuard.TUnion(schema) || Types.TypeGuard.TObject(schema))
64+
? Types.ObjectMap.Map<TReadonlyObject<T>>(schema, (schema) => {
65+
globalThis.Object.keys(schema.properties).forEach(key => Apply(schema.properties[key]))
66+
return schema
67+
}, {}) : Apply(schema)
68+
}

example/typedef/index.ts renamed to example/experimental/union-enum.ts

+20-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*--------------------------------------------------------------------------
22
3-
@sinclair/typebox/typedef
3+
@sinclair/typebox/experimental
44
55
The MIT License (MIT)
66
@@ -26,4 +26,22 @@ THE SOFTWARE.
2626
2727
---------------------------------------------------------------------------*/
2828

29-
export * from './typedef'
29+
import * as Types from '@sinclair/typebox'
30+
31+
// -------------------------------------------------------------------------------------
32+
// TUnionEnum
33+
// -------------------------------------------------------------------------------------
34+
export interface TUnionEnum<T extends (string | number)[]> extends Types.TSchema {
35+
[Types.Kind]: 'UnionEnum'
36+
static: T[number]
37+
enum: T
38+
}
39+
40+
/** `[Experimental]` Creates a Union type with a `enum` schema representation */
41+
export function UnionEnum<T extends (string | number)[]>(values: [...T], options: Types.SchemaOptions = {}) {
42+
function UnionEnumCheck(schema: TUnionEnum<(string | number)[]>, value: unknown) {
43+
return (typeof value === 'string' || typeof value === 'number') && schema.enum.includes(value)
44+
}
45+
if (!Types.TypeRegistry.Has('UnionEnum')) Types.TypeRegistry.Set('UnionEnum', UnionEnumCheck)
46+
return { ...options, [Types.Kind]: 'UnionEnum', enum: values } as TUnionEnum<T>
47+
}

example/legacy/index.ts renamed to example/experimental/union-oneof.ts

+17-2
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
/*--------------------------------------------------------------------------
22
3-
@sinclair/typebox/legacy
3+
@sinclair/typebox/experimental
44
55
The MIT License (MIT)
66
@@ -26,4 +26,19 @@ THE SOFTWARE.
2626
2727
---------------------------------------------------------------------------*/
2828

29-
export * from './intersect'
29+
import * as Types from '@sinclair/typebox'
30+
import { Value } from '@sinclair/typebox/value'
31+
32+
export interface TUnionOneOf<T extends Types.TSchema[]> extends Types.TSchema {
33+
[Types.Kind]: 'UnionOneOf'
34+
static: { [K in keyof T]: Types.Static<T[K]> }[number]
35+
oneOf: T
36+
}
37+
/** `[Experimental]` Creates a Union type with a `oneOf` schema representation */
38+
export function UnionOneOf<T extends Types.TSchema[]>(oneOf: [...T], options: Types.SchemaOptions = {}) {
39+
function UnionOneOfCheck(schema: TUnionOneOf<Types.TSchema[]>, value: unknown) {
40+
return 1 === schema.oneOf.reduce((acc: number, schema: any) => (Value.Check(schema, value) ? acc + 1 : acc), 0)
41+
}
42+
if (!Types.TypeRegistry.Has('UnionOneOf')) Types.TypeRegistry.Set('UnionOneOf', UnionOneOfCheck)
43+
return { ...options, [Types.Kind]: 'UnionOneOf', oneOf } as TUnionOneOf<T>
44+
}

example/formats/readme.md

+3-27
Original file line numberDiff line numberDiff line change
@@ -1,35 +1,11 @@
1-
# String Formats
1+
# Formats
22

3-
TypeBox does not implement any string formats by default. However it is possible to register user defined formats using the `FormatRegistry`. Once registered, the format becomes available to both `Value` and `TypeCompiler` modules.
3+
This example provides TypeCompiler supported versions of the `ajv-formats` package.
44

5-
## FormatRegistry
6-
7-
The following shows basic usage of the format registry
8-
9-
```typescript
10-
import { Type, FormatRegistry } from '@sinclair/typebox'
11-
import { Value } from '@sinclair/typebox/value'
12-
13-
// Register the 'foo-only' format. The format checks for 'foo' only.
14-
FormatRegistry.Set('foo-only', value => value === 'foo')
15-
16-
const T = Type.String({ format: 'foo-only' })
17-
18-
// Validate
19-
Value.Check(T, 'foo') // true
20-
Value.Check(T, 'bar') // false
21-
```
22-
23-
## Standard Formats
5+
## Standard
246

257
The `standard.ts` file provided with this example implements several standard string formats.
268

27-
```typescript
28-
import './standard'
29-
```
30-
31-
The following formats are implemented by `standard.ts`
32-
339
| Format | Description |
3410
| --- | --- |
3511
| `email` | Internet email address, see [RFC 5321, section 4.1.2.](http://tools.ietf.org/html/rfc5321#section-4.1.2) |
File renamed without changes.

0 commit comments

Comments
 (0)