UNPKG

zagora

Version:

A minimalist & robust way to create type-safe and error-safe never throwing functions & libraries in TypeScript - with input/output validation and typed errors. Based on StandardSchema-compliant validation libraries. No batteries, no routers, it's just fu

107 lines (94 loc) 3.32 kB
import type { StandardSchemaV1 } from "@standard-schema/spec"; import type { ZagoraError } from "./utils.ts"; export type ZagoraMetadata<THandler = unknown> = { inputSchema: StandardSchemaV1 | null; outputSchema: StandardSchemaV1 | null; errorSchema: Record<string, StandardSchemaV1> | null; handlerFn: THandler; }; export type ZagoraConfig = { errorsFirst?: boolean; }; /* Dual return format that supports both object and tuple destructuring */ export type ZagoraResult<TData, TErr, TIsDefined extends boolean> = [ TData, TErr, TIsDefined, ] & { data: TData; error: TErr; isDefined: TIsDefined; }; // convert union -> intersection helper export type UnionToIntersection<U> = ( U extends any ? (k: U) => void : never ) extends (k: infer I) => void ? I : never; /* Given `T` a tuple type, produce an intersection of function types that act as overloads for each prefix of T. */ export type IsOptional<T> = undefined extends T ? true : false; export type AllOptional<T extends any[]> = T extends [infer H, ...infer R] ? IsOptional<H> extends true ? AllOptional<R> : false : true; export type OverloadedByPrefixes<T extends any[], R> = UnionToIntersection< ValuePrefixes<T> extends infer P ? P extends any[] ? P extends [] ? AllOptional<T> extends true ? (...args: P) => R : never : (...args: P) => R : never : never >; export type ValidateOutput = [unknown, null] | [null, ZagoraError]; export type MaybeAsyncValidateOutput<TIsSync extends boolean> = TIsSync extends true ? ValidateOutput : Promise<ValidateOutput>; export type ValidateError = { error: unknown; isTyped: boolean }; export type MaybeAsyncValidateError<TIsSync extends boolean> = TIsSync extends true ? ValidateError : Promise<ValidateError>; /* prefixes of a value-tuple (mutable) */ export type ValuePrefixes<T extends any[]> = T extends [infer H, ...infer R] ? [] | [H, ...ValuePrefixes<R>] : []; /* Helper types for StandardSchema */ export type ZagoraInferInput<T extends StandardSchemaV1> = StandardSchemaV1.InferInput<T>; export type ZagoraInferOutput<T extends StandardSchemaV1> = StandardSchemaV1.InferOutput<T>; /* Error helper type - creates functions that return [null, error] tuples */ export type ZagoraErrorHelpers<T extends Record<string, StandardSchemaV1>> = { [K in keyof T]: ( error: Omit<ZagoraInferInput<T[K]>, "type"> ) => [null, ZagoraInferOutput<T[K]>]; }; export type ZagoraBaseResult< Output extends StandardSchemaV1 | null = null, ErrSchema extends Record<string, StandardSchemaV1> | null = null, > = ErrSchema extends Record<string, StandardSchemaV1> ? | ZagoraResult< Output extends StandardSchemaV1 ? ZagoraInferOutput<Output> : unknown, null, false > // success | ZagoraResult< null, { [K in keyof ErrSchema]: ZagoraInferOutput<ErrSchema[K]>; }[keyof ErrSchema], true > // typed error | ZagoraResult<null, ZagoraError, false> // untyped error : | ZagoraResult< Output extends StandardSchemaV1 ? ZagoraInferOutput<Output> : unknown, null, false > // success | ZagoraResult<null, ZagoraError, false>; // untyped error