Skip to content

Commit

Permalink
Add ConstructorCall and FunctionCall
Browse files Browse the repository at this point in the history
  • Loading branch information
sinclairzx81 committed May 4, 2024
1 parent 9759cdd commit 214de79
Show file tree
Hide file tree
Showing 16 changed files with 185 additions and 110 deletions.
39 changes: 25 additions & 14 deletions example/index.ts
Original file line number Diff line number Diff line change
@@ -1,18 +1,29 @@
import { TypeSystem } from '@sinclair/typebox/system'
import { TypeCompiler } from '@sinclair/typebox/compiler'
import { Value, ValuePointer } from '@sinclair/typebox/value'
import { Type, TypeGuard, KindGuard, Kind, Static, TSchema } from '@sinclair/typebox'
import { Type, TypeRegistry, Kind, TSchema, SchemaOptions } from '@sinclair/typebox'
import { Value } from '@sinclair/typebox/value'

const T = Type.Object({
getTime: Type.Call([], Type.Number()),
})
// Tests:
// - Check
// - Create
// - Transform.Has
// Todo:
// - Propogation of This into nested Constructor / Function calls

type T = Static<typeof T>
export class Foo {
constructor(public a: number) {
console.log('Inside Consructor', a)
}
method(a: number) {
console.log('Inside Method', a, this)
}
}
// prettier-ignore
const T = Type.ConstructorCall([1], Type.Object({
method: Type.FunctionCall(null, [2], Type.Number())
}))

// inferred: type Date = {
// getTime: () => number;
// }
const C = Value.Create(T)

const C = Type.Construct([], Type.String())
console.log(TypeGuard.IsConstruct(C))
console.log(C)
const X = new C(1)
console.log(X.method(12))

console.log(Value.Check(T, Foo))
Original file line number Diff line number Diff line change
Expand Up @@ -34,31 +34,31 @@ import { Clone } from '../clone/value'
import { Kind } from '../symbols/index'

// ------------------------------------------------------------------
// StaticConstruct
// StaticConstructorCall
// ------------------------------------------------------------------
type StaticInstanceType<U extends TSchema, P extends unknown[]> = Static<U, P>

// prettier-ignore
type StaticConstruct<T extends unknown[], U extends TSchema, P extends unknown[]> =
type StaticConstructorCall<T extends unknown[], U extends TSchema, P extends unknown[]> = (
Ensure<new (...param: [...T]) => StaticInstanceType<U, P>>

)
// ------------------------------------------------------------------
// TConstruct
// TConstructorCall
// ------------------------------------------------------------------
export interface TConstruct<T extends unknown[] = unknown[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Construct'
static: StaticConstruct<T, U, this['params']>
construct: {
export interface TConstructorCall<T extends unknown[] = unknown[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'ConstructorCall'
static: StaticConstructorCall<T, U, this['params']>
constructorCall: {
parameters: [...T]
returns: U
}
}
/** `[JavaScript]` Creates a Construct type */
export function Construct<T extends unknown[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TConstruct<T, U> {
/** `[JavaScript]` Creates a ConstructorCall type */
export function ConstructorCall<T extends unknown[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TConstructorCall<T, U> {
return {
...options,
[Kind]: 'Construct',
construct: {
[Kind]: 'ConstructorCall',
constructorCall: {
parameters: Clone(parameters),
returns: CloneType(returns),
},
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

export * from './construct'
export * from './constructor-call'
27 changes: 10 additions & 17 deletions src/type/call/call.ts → src/type/function-call/function-call.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,37 +30,30 @@ import type { TSchema, SchemaOptions } from '../schema/index'
import type { Static } from '../static/index'
import type { Ensure } from '../helpers/index'
import { CloneType } from '../clone/type'
import { Clone } from '../clone/value'
import { Kind } from '../symbols/index'

// ------------------------------------------------------------------
// StaticCall
// StaticFunctionCall
// ------------------------------------------------------------------
type StaticReturnType<U extends TSchema, P extends unknown[]> = Static<U, P>

// prettier-ignore
type StaticCall<T extends unknown[], U extends TSchema, P extends unknown[]> =
type StaticFunctionCall<T extends unknown[], U extends TSchema, P extends unknown[]> =
Ensure<(...param: [...T]) => StaticReturnType<U, P>>

// ------------------------------------------------------------------
// TCall
// TFunctionCall
// ------------------------------------------------------------------
export interface TCall<T extends unknown[] = unknown[], U extends TSchema = TSchema> extends TSchema {
export interface TFunctionCall<T extends unknown[] = unknown[], U extends TSchema = TSchema> extends TSchema {
[Kind]: 'Call'
static: StaticCall<T, U, this['params']>
call: {
static: StaticFunctionCall<T, U, this['params']>
functionCall: {
thisArg: unknown
parameters: [...T]
returns: U
}
}
/** `[JavaScript]` Creates a Call type */
export function Call<T extends unknown[], U extends TSchema>(parameters: [...T], returns: U, options?: SchemaOptions): TCall<T, U> {
return {
...options,
[Kind]: 'Call',
call: {
parameters: Clone(parameters),
returns: CloneType(returns),
},
} as never
/** `[JavaScript]` Creates a FunctionCall type */
export function FunctionCall<T extends unknown[], U extends TSchema>(thisArg: unknown, parameters: [...T], returns: U, options?: SchemaOptions): TFunctionCall<T, U> {
return { ...options, [Kind]: 'FunctionCall', functionCall: { thisArg, parameters, returns: CloneType(returns) } } as never
}
2 changes: 1 addition & 1 deletion src/type/call/index.ts → src/type/function-call/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -26,4 +26,4 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

export * from './call'
export * from './function-call'
18 changes: 9 additions & 9 deletions src/type/guard/kind.ts
Original file line number Diff line number Diff line change
Expand Up @@ -38,10 +38,10 @@ import type { TUnion } from '../union/index'
import type { TAny } from '../any/index'
import type { TAsyncIterator } from '../async-iterator/index'
import type { TBigInt } from '../bigint/index'
import type { TCall } from '../call/index'
import type { TConstruct } from '../construct/index'
import type { TConstructor } from '../constructor/index'
import type { TConstructorCall } from '../constructor-call/index'
import type { TFunction } from '../function/index'
import type { TFunctionCall } from '../function-call/index'
import type { TInteger } from '../integer/index'
import type { TIntersect } from '../intersect/index'
import type { TIterator } from '../iterator/index'
Expand Down Expand Up @@ -96,18 +96,18 @@ export function IsBigInt(value: unknown): value is TBigInt {
export function IsBoolean(value: unknown): value is TBoolean {
return IsKindOf(value, 'Boolean')
}
/** `[Kind-Only]` Returns true if the given value is TCall */
export function IsCall(value: unknown): value is TCall {
return IsKindOf(value, 'Call')
}
/** `[Kind-Only]` Returns true if the given value is TConstruct */
export function IsConstruct(value: unknown): value is TConstruct {
return IsKindOf(value, 'Construct')
/** `[Kind-Only]` Returns true if the given value is TFunctionCall */
export function IsFunctionCall(value: unknown): value is TFunctionCall {
return IsKindOf(value, 'FunctionCall')
}
/** `[Kind-Only]` Returns true if the given value is TConstructor */
export function IsConstructor(value: unknown): value is TConstructor {
return IsKindOf(value, 'Constructor')
}
/** `[Kind-Only]` Returns true if the given value is TConstructorCall */
export function IsConstructorCall(value: unknown): value is TConstructorCall {
return IsKindOf(value, 'ConstructorCall')
}
/** `[Kind-Only]` Returns true if the given value is TDate */
export function IsDate(value: unknown): value is TDate {
return IsKindOf(value, 'Date')
Expand Down
61 changes: 31 additions & 30 deletions src/type/guard/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -39,10 +39,10 @@ import type { TUnion } from '../union/index'
import type { TAny } from '../any/index'
import type { TAsyncIterator } from '../async-iterator/index'
import type { TBigInt } from '../bigint/index'
import type { TCall } from '../call/index'
import type { TConstruct } from '../construct/index'
import type { TConstructor } from '../constructor/index'
import type { TConstructorCall } from '../constructor-call/index'
import type { TFunction } from '../function/index'
import type { TFunctionCall } from '../function-call/index'
import type { TInteger } from '../integer/index'
import type { TIntersect } from '../intersect/index'
import type { TIterator } from '../iterator/index'
Expand Down Expand Up @@ -218,34 +218,6 @@ export function IsBoolean(value: unknown): value is TBoolean {
IsOptionalString(value.$id)
)
}
/** Returns true if the given value is TCall */
export function IsCall(value: unknown): value is TCall {
// prettier-ignore
return (
IsKindOf(value, 'Call') &&
ValueGuard.HasPropertyKey(value, 'call') &&
ValueGuard.IsObject(value.call) && (
ValueGuard.HasPropertyKey(value.call, 'parameters') &&
ValueGuard.HasPropertyKey(value.call, 'returns') &&
ValueGuard.IsArray(value.call.parameters) &&
IsSchema(value.call.returns)
)
)
}
/** Returns true if the given value is TConstruct */
export function IsConstruct(value: unknown): value is TConstruct {
// prettier-ignore
return (
IsKindOf(value, 'Construct') &&
ValueGuard.HasPropertyKey(value, 'construct') &&
ValueGuard.IsObject(value.construct) && (
ValueGuard.HasPropertyKey(value.construct, 'parameters') &&
ValueGuard.HasPropertyKey(value.construct, 'returns') &&
ValueGuard.IsArray(value.construct.parameters) &&
IsSchema(value.construct.returns)
)
)
}
/** Returns true if the given value is TConstructor */
export function IsConstructor(value: unknown): value is TConstructor {
// prettier-ignore
Expand All @@ -258,6 +230,20 @@ export function IsConstructor(value: unknown): value is TConstructor {
IsSchema(value.returns)
)
}
/** Returns true if the given value is TConstructorCall */
export function IsConstructorCall(value: unknown): value is TConstructorCall {
// prettier-ignore
return (
IsKindOf(value, 'ConstructorCall') &&
ValueGuard.HasPropertyKey(value, 'constructorCall') &&
ValueGuard.IsObject(value.constructorCall) && (
ValueGuard.HasPropertyKey(value.constructorCall, 'parameters') &&
ValueGuard.HasPropertyKey(value.constructorCall, 'returns') &&
ValueGuard.IsArray(value.constructorCall.parameters) &&
IsSchema(value.constructorCall.returns)
)
)
}
/** Returns true if the given value is TDate */
export function IsDate(value: unknown): value is TDate {
return (
Expand All @@ -283,6 +269,21 @@ export function IsFunction(value: unknown): value is TFunction {
IsSchema(value.returns)
)
}
/** Returns true if the given value is TFunctionCall */
export function IsFunctionCall(value: unknown): value is TFunctionCall {
// prettier-ignore
return (
IsKindOf(value, 'FunctionCall') &&
ValueGuard.HasPropertyKey(value, 'functionCall') &&
ValueGuard.IsObject(value.functionCall) && (
ValueGuard.HasPropertyKey(value.functionCall, 'thisArg') &&
ValueGuard.HasPropertyKey(value.functionCall, 'parameters') &&
ValueGuard.HasPropertyKey(value.functionCall, 'returns') &&
ValueGuard.IsArray(value.functionCall.parameters) &&
IsSchema(value.functionCall.returns)
)
)
}
/** Returns true if the given value is TInteger */
export function IsInteger(value: unknown): value is TInteger {
return (
Expand Down
4 changes: 2 additions & 2 deletions src/type/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,11 @@ export * from './async-iterator/index'
export * from './awaited/index'
export * from './bigint/index'
export * from './boolean/index'
export * from './call/index'
export * from './clone/index'
export * from './composite/index'
export * from './const/index'
export * from './construct/index'
export * from './constructor/index'
export * from './constructor-call/index'
export * from './constructor-parameters/index'
export * from './date/index'
export * from './deref/index'
Expand All @@ -48,6 +47,7 @@ export * from './exclude/index'
export * from './extends/index'
export * from './extract/index'
export * from './function/index'
export * from './function-call/index'
export * from './guard/index'
export * from './helpers/index'
export * from './indexed/index'
Expand Down
16 changes: 8 additions & 8 deletions src/type/parameters/parameters.ts
Original file line number Diff line number Diff line change
Expand Up @@ -27,44 +27,44 @@ THE SOFTWARE.
---------------------------------------------------------------------------*/

import type { TSchema, SchemaOptions } from '../schema/index'
import { type TConst, Const } from '../const'
import { type TConst, Const } from '../const/index'
import { type TTuple, Tuple } from '../tuple/index'
import type { TFunction } from '../function/index'
import type { TCall } from '../call/index'
import type { TFunctionCall } from '../function-call/index'
import { CloneRest } from '../clone/type'
import { Clone } from '../clone/value'

// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsCall, IsFunction } from '../guard/kind'
import { IsFunction, IsFunctionCall } from '../guard/kind'

// ------------------------------------------------------------------
// CallParameters
// ------------------------------------------------------------------
// prettier-ignore
type TCallParameters<T extends unknown[], Acc extends TSchema[] = []> =
type TFunctionCallParameters<T extends unknown[], Acc extends TSchema[] = []> =
T extends [infer L extends unknown, ...infer R extends unknown[]]
? TCallParameters<R, [...Acc, TConst<L>]>
? TFunctionCallParameters<R, [...Acc, TConst<L>]>
: Acc
// prettier-ignore
function CallParameters<T extends unknown[]>(parameters: T): TCallParameters<T> {
function FunctionCallParameters<T extends unknown[]>(parameters: T): TFunctionCallParameters<T> {
return parameters.map(parameter => Const(parameter)) as never
}
// ------------------------------------------------------------------
// Parameters
// ------------------------------------------------------------------
// prettier-ignore
export type TParameters<T extends TSchema> = (
T extends TCall<infer S extends unknown[]> ? TTuple<TCallParameters<S>> :
T extends TFunctionCall<infer S extends unknown[]> ? TTuple<TFunctionCallParameters<S>> :
T extends TFunction<infer S> ? TTuple<S> :
TTuple<[]>
)
/** `[JavaScript]` Extracts the Parameters from the given Function or Call type */
export function Parameters<T extends TSchema>(schema: T, options: SchemaOptions = {}): TParameters<T> {
// prettier-ignore
return (
IsCall(schema) ? Tuple(CallParameters(Clone(schema.call.parameters)), options) :
IsFunctionCall(schema) ? Tuple(FunctionCallParameters(Clone(schema.functionCall.parameters)), options) :
IsFunction(schema) ? Tuple(CloneRest(schema.parameters), options) :
Tuple([])
) as never
Expand Down
8 changes: 4 additions & 4 deletions src/type/return-type/return-type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -28,30 +28,30 @@ THE SOFTWARE.

import type { TSchema, SchemaOptions } from '../schema/index'
import { type TFunction } from '../function/index'
import { type TCall } from '../call/index'
import { type TFunctionCall } from '../function-call/index'
import { type TNever, Never } from '../never/index'
import { CloneType } from '../clone/type'

// ------------------------------------------------------------------
// TypeGuard
// ------------------------------------------------------------------
import { IsFunction, IsCall } from '../guard/kind'
import { IsFunction, IsFunctionCall } from '../guard/kind'

// ------------------------------------------------------------------
// ReturnType
// ------------------------------------------------------------------
// prettier-ignore
export type TReturnType<T extends TSchema> =
T extends TFunctionCall<infer _, infer S> ? S :
T extends TFunction<infer _, infer S> ? S :
T extends TCall<infer _, infer S> ? S :
TNever

/** `[JavaScript]` Extracts the ReturnType from the given Function or Call type */
export function ReturnType<T extends TSchema>(schema: T, options: SchemaOptions = {}): TReturnType<T> {
// prettier-ignore
return CloneType((
IsFunctionCall(schema) ? schema.call.returns :
IsFunction(schema) ? schema.returns :
IsCall(schema) ? schema.call.returns :
Never()
), options) as never
}

0 comments on commit 214de79

Please sign in to comment.