Skip to content

Commit

Permalink
use readOnly annotation on Type.Readonly | support writeOnly annotati…
Browse files Browse the repository at this point in the history
…on on schema options
  • Loading branch information
sinclairzx81 committed Jul 22, 2023
1 parent 000bc0a commit c94a44c
Show file tree
Hide file tree
Showing 3 changed files with 32 additions and 48 deletions.
19 changes: 7 additions & 12 deletions example/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,18 +10,13 @@ import { Type, TypeGuard, Kind, Static, TSchema, Optional, Readonly } from '@sin
const ReadonlyOptional = <T extends TSchema>(schema: T) => Type.Readonly(Type.Optional(schema))

const A = Type.Object({
x: Type.Number(),
y: Type.Number(),
x: Type.Readonly(Type.Number({ writeOnly: true })),
y: Type.Number({ readOnly: true }),
z: Type.Number(),
})
const B = Type.Object({
x: Type.Number(),
y: Type.Number(),
z: Type.Number(),
})
const I = Type.Intersect([A, B])
const T = Type.Partial(I)
console.log(I)
console.log(T)

type T = Static<typeof T>
import Ajv from 'ajv'

const ajv = new Ajv()

console.log(ajv.validate(A, { x: 1, y: 2, z: 3 }))
11 changes: 1 addition & 10 deletions readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -611,21 +611,12 @@ TypeBox provides modifiers that allow schema properties to be statically inferre
Type.String() │ } │ properties: { │
│ ) │ │ name: { │
│ }) │ │ type: 'string'
│ │ │ readOnly: true
│ │ │ } │
│ │ │ }, │
│ │ │ required: ['name'] │
│ │ │ } │
│ │ │ │
├────────────────────────────────┼─────────────────────────────┼────────────────────────────────┤
const T = Type.Object({ │ type T = { │ const T = { │
│ name: Type.ReadonlyOptional( │ readonly name?: stringtype: 'object', │
Type.String() │ } │ properties: { │
│ ) │ │ name: { │
│ }) │ │ type: 'string'
│ │ │ } │
│ │ │ } │
│ │ │ } │
│ │ │ │
└────────────────────────────────┴─────────────────────────────┴────────────────────────────────┘
```
Expand Down
50 changes: 24 additions & 26 deletions src/typebox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,10 @@ export interface SchemaOptions {
default?: any
/** Example values matching this schema */
examples?: any
/** Optional annotation for readOnly */
readOnly?: boolean
/** Optional annotation for writeOnly */
writeOnly?: boolean
[prop: string]: any
}
export interface TKind {
Expand Down Expand Up @@ -2457,14 +2461,14 @@ export class StandardTypeBuilder extends TypeBuilder {
// ------------------------------------------------------------------------
// Modifiers
// ------------------------------------------------------------------------
/** `[Standard]` Creates a Readonly property */
public Readonly<T extends TSchema>(schema: T): TReadonly<T> {
return { ...TypeClone.Clone(schema, {}), [Readonly]: 'Readonly', readOnly: true }
}
/** `[Standard]` Creates an Optional property */
public Optional<T extends TSchema>(schema: T): TOptional<T> {
return { ...TypeClone.Clone(schema, {}), [Optional]: 'Optional' }
}
/** `[Standard]` Creates a Readonly property */
public Readonly<T extends TSchema>(schema: T): TReadonly<T> {
return { ...TypeClone.Clone(schema, {}), [Readonly]: 'Readonly' }
}
// ------------------------------------------------------------------------
// Types
// ------------------------------------------------------------------------
Expand Down Expand Up @@ -2656,17 +2660,14 @@ export class StandardTypeBuilder extends TypeBuilder {
}
/** `[Standard]` Creates a mapped type where all properties are Optional */
public Partial<T extends TSchema>(schema: T, options: ObjectOptions = {}): TPartial<T> {
return ObjectMap.Map(
schema,
(object) => {
const properties = globalThis.Object.keys(object.properties).reduce((acc, key) => {
return { ...acc, [key]: this.Optional(object.properties[key]) }
}, {} as TProperties)
const { required: _, ...rest } = schema
return this.Object(properties, { ...rest })
},
options,
)
// prettier-ignore
return ObjectMap.Map(schema, (object) => {
const properties = globalThis.Object.getOwnPropertyNames(object.properties).reduce((acc, key) => {
return { ...acc, [key]: this.Optional(object.properties[key]) }
}, {} as TProperties)
const { required: _, ...rest } = schema
return this.Object(properties, { ...rest })
}, options)
}
/** `[Standard]` Creates a mapped type whose keys are picked from the given type */
public Pick<T extends TSchema, K extends (keyof Static<T>)[]>(schema: T, keys: readonly [...K], options?: SchemaOptions): TPick<T, K[number]>
Expand Down Expand Up @@ -2744,17 +2745,14 @@ export class StandardTypeBuilder extends TypeBuilder {
}
/** `[Standard]` Creates a mapped type where all properties are Required */
public Required<T extends TSchema>(schema: T, options: SchemaOptions = {}): TRequired<T> {
return ObjectMap.Map(
schema,
(object) => {
const properties = globalThis.Object.keys(object.properties).reduce((acc, key) => {
const { [Optional]: _, ...rest } = object.properties[key]
return { ...acc, [key]: rest }
}, {} as TProperties)
return this.Object(properties, { ...schema })
},
options,
)
// prettier-ignore
return ObjectMap.Map(schema, (object) => {
const properties = globalThis.Object.keys(object.properties).reduce((acc, key) => {
const { [Optional]: _, ...rest } = object.properties[key]
return { ...acc, [key]: rest }
}, {} as TProperties)
return this.Object(properties, { ...schema })
}, options)
}
/** `[Standard]` Returns a schema array which allows types to compose with the JavaScript spread operator */
public Rest<T extends TSchema>(schema: T): TRest<T> {
Expand Down

0 comments on commit c94a44c

Please sign in to comment.