Skip to content

Commit

Permalink
Support Optional and Readonly Function Arguments
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed Apr 20, 2024
1 parent bcee7b5 commit c50745a
Show file tree
Hide file tree
Showing 4 changed files with 77 additions and 16 deletions.
25 changes: 17 additions & 8 deletions src/type/constructor/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,37 @@ THE SOFTWARE.
import type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import type { TReadonlyOptional } from '../readonly-optional/index'
import type { TReadonly } from '../readonly/index'
import type { TOptional } from '../optional/index'
import { CloneType, CloneRest } from '../clone/type'
import { Kind } from '../symbols/index'

// ------------------------------------------------------------------
// TConstructorStatic
// StaticFunction
// ------------------------------------------------------------------
type ConstructorStaticReturnType<T extends TSchema, P extends unknown[]> = Static<T, P>
type StaticReturnType<U extends TSchema, P extends unknown[]> = Static<U, P>
// prettier-ignore
type ConstructorStaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> =
type StaticParameter<T extends TSchema, P extends unknown[]> =
T extends TReadonlyOptional<T> ? [Readonly<Static<T, P>>?] :
T extends TReadonly<T> ? [Readonly<Static<T, P>>] :
T extends TOptional<T> ? [Static<T, P>?] :
[Static<T, P>]
// prettier-ignore
type StaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? ConstructorStaticParameters<R, P, [...Acc, Static<L, P>]>
? StaticParameters<R, P, [...Acc, ...StaticParameter<L, P>]>
: Acc
// prettier-ignore
type ConstructorStatic<T extends TSchema[], U extends TSchema, P extends unknown[]> = (
Ensure<new (...param: ConstructorStaticParameters<T, P>) => ConstructorStaticReturnType<U, P>>
)
// prettier-ignore
type StaticConstructor<T extends TSchema[], U extends TSchema, P extends unknown[]> =
Ensure<new (...params: StaticParameters<T, P>) => StaticReturnType<U, P>>
// ------------------------------------------------------------------
// TConstructor
// ------------------------------------------------------------------
export interface TConstructor<T extends TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Constructor'
static: ConstructorStatic<T, U, this['params']>
static: StaticConstructor<T, U, this['params']>
type: 'Constructor'
parameters: T
returns: U
Expand Down
26 changes: 18 additions & 8 deletions src/type/function/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -29,28 +29,38 @@ THE SOFTWARE.
import type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import type { TReadonlyOptional } from '../readonly-optional/index'
import type { TReadonly } from '../readonly/index'
import type { TOptional } from '../optional/index'
import { CloneType, CloneRest } from '../clone/type'
import { Kind } from '../symbols/index'

// ------------------------------------------------------------------
// FunctionStatic
// StaticFunction
// ------------------------------------------------------------------
type FunctionStaticReturnType<T extends TSchema, P extends unknown[]> = Static<T, P>
type StaticReturnType<U extends TSchema, P extends unknown[]> = Static<U, P>
// prettier-ignore
type FunctionStaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> =
type StaticParameter<T extends TSchema, P extends unknown[]> =
T extends TReadonlyOptional<T> ? [Readonly<Static<T, P>>?] :
T extends TReadonly<T> ? [Readonly<Static<T, P>>] :
T extends TOptional<T> ? [Static<T, P>?] :
[Static<T, P>]
// prettier-ignore
type StaticParameters<T extends TSchema[], P extends unknown[], Acc extends unknown[] = []> = (
T extends [infer L extends TSchema, ...infer R extends TSchema[]]
? FunctionStaticParameters<R, P, [...Acc, Static<L, P>]>
? StaticParameters<R, P, [...Acc, ...StaticParameter<L, P>]>
: Acc
// prettier-ignore
type FunctionStatic<T extends TSchema[], U extends TSchema, P extends unknown[]> = (
Ensure<(...param: FunctionStaticParameters<T, P>) => FunctionStaticReturnType<U, P>>
)
// prettier-ignore
type StaticFunction<T extends TSchema[], U extends TSchema, P extends unknown[]> =
Ensure<(...params: StaticParameters<T, P>) => StaticReturnType<U, P>>

// ------------------------------------------------------------------
// TFunction
// ------------------------------------------------------------------
export interface TFunction<T extends TSchema[] = TSchema[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Function'
static: FunctionStatic<T, U, this['params']>
static: StaticFunction<T, U, this['params']>
type: 'Function'
parameters: T
returns: U
Expand Down
20 changes: 20 additions & 0 deletions test/static/constructor.ts
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,26 @@ import { Type } from '@sinclair/typebox'
}))
Expect(T).ToStatic<new (param_0: number, param_1: string) => { method: new (param_0: number, param_1: string) => boolean }>()
}
{
// readonly-optional
const T = Type.Constructor([Type.ReadonlyOptional(Type.Array(Type.Number()))], Type.Number())
Expect(T).ToStaticDecode<new (param_0?: readonly number[]) => number>()
}
{
// readonly
const T = Type.Constructor([Type.Readonly(Type.Array(Type.Number()))], Type.Number())
Expect(T).ToStaticDecode<new (param_0: readonly number[]) => number>()
}
{
// optional 1
const T = Type.Constructor([Type.Optional(Type.Number())], Type.Number())
Expect(T).ToStaticDecode<new (param_0?: number) => number>()
}
{
// optional 2
const T = Type.Constructor([Type.Number(), Type.Optional(Type.Number())], Type.Number())
Expect(T).ToStaticDecode<new (param_0: number, param_1?: number) => number>()
}
{
// decode 2
const S = Type.Transform(Type.Integer())
Expand Down
22 changes: 22 additions & 0 deletions test/static/function.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,28 @@ import { Type } from '@sinclair/typebox'
}))
Expect(T).ToStatic<(param_0: number, param_1: string) => { method: (param_0: number, param_1: string) => boolean }>()
}
{
// readonly-optional
const T = Type.Function([Type.ReadonlyOptional(Type.Array(Type.Number()))], Type.Number())
Expect(T).ToStaticDecode<(param_0?: readonly number[]) => number>()
}
{
// readonly
const T = Type.Function([Type.Readonly(Type.Array(Type.Number()))], Type.Number())
Expect(T).ToStaticDecode<(param_0: readonly number[]) => number>()
}
{
// optional 1
const T = Type.Function([Type.Optional(Type.Number())], Type.Number())
Expect(T).ToStaticDecode<(param_0?: number) => number>()
}
{
// optional 2
const T = Type.Function([Type.Number(), Type.Optional(Type.Number())], Type.Number())
Expect(T).ToStaticDecode<(param_0: number, param_1?: number) => number>()
}
const F = Type.Constructor([Type.Readonly(Type.Array(Type.String()))], Type.Number())

{
// decode 2
const S = Type.Transform(Type.Integer())
Expand Down

0 comments on commit c50745a

Please sign in to comment.