Skip to content

Commit

Permalink
Revision 0.31.6 (#560)
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 authored Aug 29, 2023
1 parent dd71b52 commit 67925c1
Show file tree
Hide file tree
Showing 6 changed files with 79 additions and 34 deletions.
4 changes: 2 additions & 2 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "@sinclair/typebox",
"version": "0.31.5",
"version": "0.31.6",
"description": "JSONSchema Type Builder with Static Type Resolution for TypeScript",
"keywords": [
"typescript",
Expand Down
47 changes: 22 additions & 25 deletions src/typebox.ts
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ export type AssertType<T, E extends TSchema = TSchema> = T extends E ? T : TNeve
// --------------------------------------------------------------------------
// Modifiers
// --------------------------------------------------------------------------
export type TModifier = TOptional<TSchema> | TReadonly<TSchema>
export type TReadonlyOptional<T extends TSchema> = TOptional<T> & TReadonly<T>
export type TReadonly<T extends TSchema> = T & { [Readonly]: 'Readonly' }
export type TOptional<T extends TSchema> = T & { [Optional]: 'Optional' }
// --------------------------------------------------------------------------
Expand Down Expand Up @@ -855,37 +855,34 @@ export interface TTemplateLiteral<T extends TTemplateLiteralKind[] = TTemplateLi
// TTransform
// --------------------------------------------------------------------------
// prettier-ignore
export type DecodeModifier<D extends TSchema, T extends TSchema> =
T extends TReadonly<T> & TOptional<T> ? TReadonly<TOptional<D>> :
T extends TReadonly<T> ? TReadonly<D> :
T extends TOptional<T> ? TOptional<D> :
D
// prettier-ignore
export type DecodeProperties<T extends TProperties> = {
[K in keyof T]: DecodeType<T[K]>
}
// prettier-ignore
export type DecodeRest<T extends TSchema[]> = T extends [infer L, ...infer R]
? [DecodeType<AssertType<L>>, ...DecodeRest<AssertRest<R>>]
export type DecodeRest<T extends TSchema[]> = T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? [DecodeType<L>, ...DecodeRest<R>]
: []
// prettier-ignore
export type DecodeType<T extends TSchema> =
T extends TTransform<infer _, infer R> ? DecodeModifier<TUnsafe<R>, T> :
T extends TArray<infer S> ? DecodeModifier<TArray<DecodeType<S>>, T> :
T extends TAsyncIterator<infer S> ? DecodeModifier<TAsyncIterator<DecodeType<S>>, T> :
T extends TConstructor<infer P, infer R> ? DecodeModifier<TConstructor<AssertRest<DecodeRest<P>>, DecodeType<R>>, T> :
T extends TFunction<infer P, infer R> ? DecodeModifier<TFunction<AssertRest<DecodeRest<P>>, DecodeType<R>>, T> :
T extends TIntersect<infer S> ? DecodeModifier<TIntersect<AssertRest<DecodeRest<S>>>, T> :
T extends TIterator<infer S> ? DecodeModifier<TIterator<DecodeType<S>>, T> :
T extends TNot<infer S> ? DecodeModifier<TNot<DecodeType<S>>, T> :
T extends TObject<infer S> ? DecodeModifier<TObject<Evaluate<DecodeProperties<S>>>, T> :
T extends TPromise<infer S> ? DecodeModifier<TPromise<DecodeType<S>>, T> :
T extends TRecord<infer K, infer S> ? DecodeModifier<TRecord<K, DecodeType<S>>, T> :
T extends TRecursive<infer S> ? DecodeModifier<TRecursive<DecodeType<S>>, T> :
T extends TRef<infer S> ? DecodeModifier<TRef<DecodeType<S>>, T> :
T extends TTuple<infer S> ? DecodeModifier<TTuple<AssertRest<DecodeRest<S>>>, T> :
T extends TUnion<infer S> ? DecodeModifier<TUnion<AssertRest<DecodeRest<S>>>, T> :
export type DecodeType<T extends TSchema> = (
T extends TOptional<infer S extends TSchema> ? TOptional<DecodeType<S>> :
T extends TReadonly<infer S extends TSchema> ? TReadonly<DecodeType<S>> :
T extends TTransform<infer _, infer R> ? TUnsafe<R> :
T extends TArray<infer S extends TSchema> ? Array<DecodeType<S>> :
T extends TAsyncIterator<infer S extends TSchema> ? TAsyncIterator<DecodeType<S>> :
T extends TConstructor<infer P extends TSchema[], infer R extends TSchema> ? TConstructor<P, DecodeType<R>> :
T extends TFunction<infer P extends TSchema[], infer R extends TSchema> ? TFunction<P, DecodeType<R>> :
T extends TIntersect<infer S extends TSchema[]> ? TIntersect<S> :
T extends TIterator<infer S extends TSchema> ? TIterator<DecodeType<S>> :
T extends TNot<infer S extends TSchema> ? TNot<DecodeType<S>> :
T extends TObject<infer S> ? TObject<Evaluate<DecodeProperties<S>>> :
T extends TPromise<infer S extends TSchema> ? TPromise<DecodeType<S>> :
T extends TRecord<infer K, infer S> ? TRecord<K, DecodeType<S>> :
T extends TRecursive<infer S extends TSchema> ? TRecursive<DecodeType<S>> :
T extends TRef<infer S extends TSchema> ? TRef<DecodeType<S>> :
T extends TTuple<infer S extends TSchema[]> ? TTuple<S> :
T extends TUnion<infer S extends TSchema[]> ? TUnion<S> :
T
)
export type TransformFunction<T = any, U = any> = (value: T) => U
export interface TransformOptions<I extends TSchema = TSchema, O extends unknown = unknown> {
Decode: TransformFunction<StaticDecode<I>, O>
Expand Down
8 changes: 4 additions & 4 deletions src/value/value.ts
Original file line number Diff line number Diff line change
Expand Up @@ -78,19 +78,19 @@ export namespace Value {
return ValueClone.Clone(value)
}
/** Decodes a value or throws if error */
export function Decode<T extends Types.TSchema>(schema: T, references: Types.TSchema[], value: unknown): Types.StaticDecode<T>
export function Decode<T extends Types.TSchema, D = Types.StaticDecode<T>>(schema: T, references: Types.TSchema[], value: unknown): D
/** Decodes a value or throws if error */
export function Decode<T extends Types.TSchema>(schema: T, value: unknown): Types.StaticDecode<T>
export function Decode<T extends Types.TSchema, D = Types.StaticDecode<T>>(schema: T, value: unknown): D
/** Decodes a value or throws if error */
export function Decode(...args: any[]) {
const [schema, references, value] = args.length === 3 ? [args[0], args[1], args[2]] : [args[0], [], args[1]]
if (!Check(schema, references, value)) throw new ValueTransform.TransformDecodeCheckError(schema, value, Errors(schema, references, value).First()!)
return ValueTransform.DecodeTransform.Decode(schema, references, value, ValueCheck.Check)
}
/** Encodes a value or throws if error */
export function Encode<T extends Types.TSchema>(schema: T, references: Types.TSchema[], value: unknown): Types.StaticEncode<T>
export function Encode<T extends Types.TSchema, E = Types.StaticEncode<T>>(schema: T, references: Types.TSchema[], value: unknown): E
/** Encodes a value or throws if error */
export function Encode<T extends Types.TSchema>(schema: T, value: unknown): Types.StaticEncode<T>
export function Encode<T extends Types.TSchema, E = Types.StaticEncode<T>>(schema: T, value: unknown): E
/** Encodes a value or throws if error */
export function Encode(...args: any[]) {
const [schema, references, value] = args.length === 3 ? [args[0], args[1], args[2]] : [args[0], [], args[1]]
Expand Down
19 changes: 18 additions & 1 deletion test/static/readonly-optional.ts
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
import { Expect } from './assert'
import { Type, TSchema } from '@sinclair/typebox'
import { Type, TSchema, TReadonlyOptional } from '@sinclair/typebox'

{
const T = Type.Object({
Expand All @@ -9,3 +9,20 @@ import { Type, TSchema } from '@sinclair/typebox'
readonly A?: string
}>()
}
{
const T = Type.ReadonlyOptional(Type.String())
function test(_: TReadonlyOptional<TSchema>) {}
test(T)
}
{
const T = Type.Readonly(Type.String())
function test(_: TReadonlyOptional<TSchema>) {}
// @ts-expect-error
test(T)
}
{
const T = Type.Optional(Type.String())
function test(_: TReadonlyOptional<TSchema>) {}
// @ts-expect-error
test(T)
}
33 changes: 32 additions & 1 deletion test/static/transform.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
import { Type, Static, StaticDecode, TObject, TNumber } from '@sinclair/typebox'
import { Type, TSchema, Static, StaticDecode, TObject, TNumber } from '@sinclair/typebox'
import { Expect } from './assert'
{
// string > number
Expand Down Expand Up @@ -214,3 +214,34 @@ import { Expect } from './assert'
Expect(T).ToStaticDecode<{ x: '1' }>()
Expect(T).ToStaticDecode<{ x: undefined }>()
}
{ // should decode within generic function context
// https://github.com/sinclairzx81/typebox/issues/554
// prettier-ignore
const ArrayOrSingle = <T extends TSchema>(schema: T) =>
Type.Transform(Type.Union([schema, Type.Array(schema)]))
.Decode((value) => (Array.isArray(value) ? value : [value]))
.Encode((value) => (value.length === 1 ? value[0] : value) as Static<T>[]);
const T = ArrayOrSingle(Type.String())
Expect(T).ToStaticDecode<string[]>()
}
{
// should correctly decode record keys
// https://github.com/sinclairzx81/typebox/issues/555
// prettier-ignore
const T = Type.Object({
x: Type.Optional(Type.Record(Type.Number(), Type.String()))
})
type A = StaticDecode<typeof T>
type Test<A, E> = E extends A ? true : false
type E1 = Test<A, {}>
type E2 = Test<A, { x: undefined }>
type E3 = Test<A, { x: { 1: '' } }>
type E4 = Test<A, { x: { 1: 1 } }>
type E5 = Test<A, { x: { x: 1 } }>
// assignment
const E1: E1 = true
const E2: E2 = true
const E3: E3 = true
const E4: E4 = false
const E5: E5 = true
}

0 comments on commit 67925c1

Please sign in to comment.