Skip to main content
Siglo is built from the ground up for modern TypeScript (strict mode, noImplicitAny, exactOptionalPropertyTypes).

1. Step Generics: Step<TInput, TOutput, TName>

When defining a step with Step.create(name, action):
  • TInput: Type expected by the step action parameter.
  • TOutput: Type returned by the step action.
  • TName: String literal name of the step (used to index $steps).

Generic Overloads

Step.create supports both explicit generic orders:
  1. Name-First Overload (convenient when specifying literal step name as the leading type argument):
  2. Input-First Overload (mirrors the class generic order Step<TInput, TOutput, TName>):
  3. Automatic Inference (Recommended): In standard application code, TypeScript automatically infers TName, TInput, and TOutput from the function arguments without manual type parameter annotations:

2. Accumulated Context Inference

When steps are chained in flow(s1, s2, s3):
  • Step 1 receives TIn and returns T1Out.
  • Step 2 receives TIn & T1Out and returns T2Out.
  • Step 3 receives TIn & T1Out & T2Out and returns T3Out.
  • The workflow execution returns MergeStepContext<TIn, T1Out & T2Out & T3Out> & { $steps: Record<...> }.

3. Typed Step History: $steps

Every named step automatically registers its typed output in $steps:

4. Dependency Injection Typing

Define typed runtime dependencies per-step or per-workflow:
Or attach step-level dependencies:

5. Schema Validation Support

Siglo integrates with Standard Schema (~standard) compatible libraries including Zod, Valibot, and ArkType:

Minimal Example


Compile-Time Checking & Inference Boundaries

When steps declare explicit input generic types (Step.create<MyInput, ...>), TypeScript verifies whether upstream outputs provide the required properties:
[!NOTE] Inference Limits with Combinators & Long Pipelines: Type inference works seamlessly across sequential chains. However, across dynamic combinators (branch, when, map) or deep pipelines (5+ steps), TypeScript’s conditional type evaluation may widen accumulated intersection types or infer optional properties. For ironclad parameter validation across complex combinators and untrusted ingress boundaries, pair TypeScript definitions with runtime schema assertions (step.schema() or step.spec()).

Testing Example


Operational Caveats

  1. Keep Step Generic Signatures Clean: In complex pipelines, rely on TypeScript’s inference rather than manually specifying all intermediate types for 10+ steps.
  2. Strict Mode: Ensure "strict": true is enabled in tsconfig.json for full compile-time inference benefits.