import type { Internal } from './internal/types.ts' /** * The failure case of a Result. * It has a list of Errors. */ type Failure = { success: false errors: Array } /** * The success case of a Result. * It has a generic T as the data. * It also has an empty list of errors for convenience. */ type Success = { success: true data: T errors: [] } /** * The output of a computation that might fail. */ type Result = Success | Failure /** * Merges the data types of a list of objects. * @example * type MyObjs = [ * { a: string }, * { b: number }, * ] * type MyData = MergeObjects * // ^? { a: string, b: number } */ type MergeObjects = Objs extends [ infer first, ...infer rest, ] ? MergeObjects & first>> : output /** * A composable async function that catches failures. * We only use this type to make the Composable type neater looking, use `Composable` instead. * It does not need to be exported by the library. */ type ComposableFunction = { ( ...args: Parameters ): Promise>>> kind: 'composable' } /** * A composable async function that catches failures. */ type Composable = T extends { kind: 'composable' } ? T : ComposableFunction /** * A composable async function with schema validation at runtime. */ type ComposableWithSchema = Composable< (input?: unknown, context?: unknown) => O > /** * Extract the type of the returned data when a Composable is successful. */ type UnpackData = Extract< Awaited>, { success: true } >['data'] /** * Extracts the types of successful data returned by multiple Composables. */ type UnpackAll = { [K in keyof List]: UnpackData } /** * A Composable that represents the sequential execution of multiple Composables. * The return type is a tuple with all results on the success data. * This type can resolve to a FailToCompose when the composition won't type-check. */ type SequenceReturn = Fns extends [ Composable<(...args: infer P) => any>, ...any, ] ? Composable<(...args: P) => UnpackAll> : Fns /** * A Composable that represents the sequential execution of multiple Composables. * The return type is the success data of the last function in the chain. * This type can resolve to a FailToCompose when the composition won't type-check. */ type PipeReturn = Fns extends [ Composable<(...args: infer P) => any>, ...any, ] ? Composable<(...args: P) => UnpackData, Composable>>> : Fns /** * Determines whether a sequence of Composables can be composed sequentially. */ type CanComposeInSequence< Fns extends unknown[], Arguments extends unknown[] = [], > = Fns extends [Composable<(...a: infer PA) => infer OA>, ...infer restA] ? restA extends [ Composable< (firstParameter: infer FirstBParameter, ...b: infer PB) => any >, ...unknown[], ] ? Internal.IsNever> extends true ? Internal.FailToCompose : Awaited extends FirstBParameter ? Internal.EveryElementTakes extends true ? CanComposeInSequence< restA, [...Arguments, Composable<(...a: PA) => OA>] > : Internal.EveryElementTakes : Internal.FailToCompose, FirstBParameter> : [...Arguments, Composable<(...a: PA) => OA>] : never /** * Determines whether a sequence of Composables can be composed in parallel. */ type CanComposeInParallel< Fns extends unknown[], OriginalFns extends unknown[] = Fns, > = Fns extends [Composable<(...a: infer PA) => unknown>, ...infer restA] ? restA extends [Composable<(...b: infer PB) => infer OB>, ...infer restB] ? Internal.SubtypesTuple extends [...infer MergedP] ? CanComposeInParallel< [Composable<(...args: MergedP) => OB>, ...restB], OriginalFns > : Internal.FailToCompose : Internal.ApplyArgumentsToFns : never /** * Transforms a record of Composables into a tuple of their return types. */ type RecordToTuple any>> = Internal.RecordValuesFromKeysTuple> /** * A serializable error object. */ type SerializableError = { exception: Error message: string name: string path: string[] } /** * The serializable output of a Result. */ type SerializableResult = | Success | { success: false; errors: SerializableError[] } /** * Returns the last element of a tuple type. */ type Last = T extends [...infer _I, infer L] ? L : never /** * A Composable that branches based on the output of another Composable. */ type BranchReturn< SourceComposable extends Composable, Resolver extends ( ...args: any[] ) => Internal.AnyFn | null | Promise, > = CanComposeInSequence< [SourceComposable, Composable] > extends Composable[] ? Awaited> extends null ? SourceComposable : CanComposeInSequence< [SourceComposable, Awaited>] > extends [Composable, ...any] ? Composable< ( ...args: Parameters< CanComposeInSequence< [SourceComposable, Awaited>] >[0] > ) => null extends Awaited> ? | UnpackData | UnpackData< Composable>>> > : UnpackData< Composable>>> > > : CanComposeInSequence< [SourceComposable, Awaited>] > : CanComposeInSequence<[SourceComposable, Composable]> /** * Ensure that schemas are compatible with composable input and context otherwise return a FailToCompose. */ type ApplySchemaReturn< ParsedInput, ParsedContext, Fn extends Internal.AnyFn, > = ParsedInput extends Parameters[0] ? ParsedContext extends Parameters[1] ? Awaited> extends never ? ComposableWithSchema : Awaited> extends Result ? ComposableWithSchema : ComposableWithSchema>> : FailToCompose[1]> : FailToCompose[0]> /** * The return type of the mapParameters function */ type MapParametersReturn< Fn extends Composable, NewParams extends unknown[], O extends Parameters, > = Composable< ( ...args: NewParams ) => Internal.IsNever extends true ? never : UnpackData > // Re-exporting internal types /** * A type that represents an error when composing functions with incompatible arguments. */ type IncompatibleArguments = Internal.IncompatibleArguments /** * This is IncompatibleArguments supertype where we include the arguments that caused the incompatibility. */ type FailToCompose = Internal.FailToCompose export type { ApplySchemaReturn, BranchReturn, CanComposeInParallel, CanComposeInSequence, Composable, ComposableWithSchema, FailToCompose, Failure, IncompatibleArguments, Last, MapParametersReturn, MergeObjects, PipeReturn, RecordToTuple, Result, SequenceReturn, SerializableError, SerializableResult, Success, UnpackAll, UnpackData, }