.do
Reference

Types Reference

Complete TypeScript types and interfaces for Business-as-Code

The Business-as-Code framework provides a comprehensive set of TypeScript types and interfaces for building autonomous business systems. This reference documents all core types, their properties, and usage patterns.

Overview

Business-as-Code uses TypeScript for full type safety across all operations. The type system is designed to be:

  • Semantic: Types carry business meaning, not just structure
  • Composable: Types can be combined and extended
  • Type-Safe: Full TypeScript inference and checking
  • Standards-Based: Built on Schema.org, O*NET, and GS1
graph TB subgraph Core["Core Types"] BF[BusinessFunction<br/>Executable operations] BW[BusinessWorkflow<br/>Multi-step processes] BA[BusinessAgent<br/>Autonomous agents] end subgraph Data["Data Types"] BR[BusinessResource<br/>Entities/nouns] BA2[BusinessAction<br/>Subject-Verb-Object] BE[BusinessEvent<br/>System events] end subgraph Query["Query Types"] BQ[BusinessQuery<br/>Search operations] BM[BusinessMetric<br/>Measurements/KPIs] end BF --> BW BW --> BA BR --> BA2 BA2 --> BE BQ --> BM

Type Categories

Execution Types

Types for defining and executing business logic:

Data Types

Types for representing business data:

Query Types

Types for querying and measuring:

Type Safety Patterns

Generic Types

Business-as-Code uses TypeScript generics for type-safe operations:

// Function with typed input and output
const calculateDiscount: BusinessFunction<{ price: number; discountPercent: number }, { finalPrice: number; saved: number }> = {
  id: 'calculate-discount',
  name: 'Calculate Discount',
  execute: async (input) => {
    const saved = input.price * (input.discountPercent / 100)
    return {
      finalPrice: input.price - saved,
      saved,
    }
  },
}

// Type inference works automatically
const result = await calculateDiscount.execute({ price: 100, discountPercent: 10 })
console.log(result.finalPrice) // TypeScript knows this is a number

Type Guards

Use type guards to narrow types safely:

function isBusinessFunction(value: unknown): value is BusinessFunction {
  return typeof value === 'object' && value !== null && 'id' in value && 'execute' in value && typeof value.execute === 'function'
}

function isBusinessWorkflow(value: unknown): value is BusinessWorkflow {
  return typeof value === 'object' && value !== null && 'id' in value && 'steps' in value && Array.isArray(value.steps)
}

// Usage
const entity = await loadEntity()
if (isBusinessFunction(entity)) {
  const result = await entity.execute(input) // Type-safe
}

Type Inference

TypeScript automatically infers types from usage:

// Input and output types are inferred
const addNumbers = {
  id: 'add',
  name: 'Add Numbers',
  execute: async (input: { a: number; b: number }) => {
    return { sum: input.a + input.b }
  },
} satisfies BusinessFunction

// TypeScript knows the return type
const result = await addNumbers.execute({ a: 1, b: 2 })
console.log(result.sum) // Type: number

Discriminated Unions

WorkflowStep uses discriminated unions for type safety:

// Different step types have different properties
type WorkflowStep =
  | {
      type: 'function'
      function: string | BusinessFunction
      condition?: never
      config?: Record<string, any>
    }
  | {
      type: 'condition'
      condition: string
      function?: never
      config?: never
    }
  | {
      type: 'agent'
      config: { agentRole: string; permissions?: string[] }
      function?: never
      condition?: never
    }

// TypeScript enforces correct properties per type
const step: WorkflowStep = {
  type: 'function',
  function: 'send-email', // Valid
  // condition: 'x > 5',  // Error: not valid for function steps
}

Integration with SDK

Types integrate seamlessly with the SDK:

import { $, db, on, send } from 'sdk.do'
import type { BusinessFunction, BusinessWorkflow, BusinessAgent } from 'business-as-code'

// Define typed function
const sendWelcomeEmail: BusinessFunction<{ email: string; name: string }, { messageId: string }> = {
  id: 'send-welcome-email',
  name: 'Send Welcome Email',
  execute: async ({ email, name }) => {
    const messageId = await send($.Email.send, {
      to: email,
      subject: `Welcome ${name}!`,
      template: 'welcome',
    })
    return { messageId }
  },
}

// Use in workflow
const onboardingWorkflow: BusinessWorkflow = {
  id: 'user-onboarding',
  name: 'User Onboarding',
  steps: [
    {
      id: 'send-email',
      name: 'Send Welcome Email',
      type: 'function',
      function: sendWelcomeEmail, // Type-safe
      next: 'assign-rep',
    },
    {
      id: 'assign-rep',
      name: 'Assign Sales Rep',
      type: 'agent',
      config: { agentRole: 'sdr' },
    },
  ],
}

Type Extensions

Extend core types for custom needs:

// Extend BusinessFunction with retry logic
interface RetryableFunction<TInput = any, TOutput = any> extends BusinessFunction<TInput, TOutput> {
  retries?: number
  retryDelay?: number
  onRetry?: (attempt: number, error: Error) => void
}

// Extend BusinessWorkflow with versioning
interface VersionedWorkflow extends BusinessWorkflow {
  version: string
  changeLog?: string[]
  deprecated?: boolean
  replacedBy?: string
}

// Extend BusinessAgent with tools
interface ToolEnabledAgent extends BusinessAgent {
  tools: {
    id: string
    name: string
    description: string
    execute: (input: any) => Promise<any>
  }[]
}

Type Utility Functions

Helper functions for working with types:

// Check if value matches type structure
export function isType<T extends { $type: string }>(value: unknown, type: string): value is T {
  return typeof value === 'object' && value !== null && '$type' in value && value.$type === type
}

// Extract input type from function
export type InputType<T> = T extends BusinessFunction<infer I, any> ? I : never

// Extract output type from function
export type OutputType<T> = T extends BusinessFunction<any, infer O> ? O : never

// Usage
type CalculateInput = InputType<typeof calculateDiscount>
// Type: { price: number; discountPercent: number }

type CalculateOutput = OutputType<typeof calculateDiscount>
// Type: { finalPrice: number; saved: number }

Best Practices

1. Use Explicit Types

Always define explicit types for function inputs and outputs:

// ✅ Good: Explicit types
interface CalculateInput {
  price: number
  quantity: number
  taxRate: number
}

interface CalculateOutput {
  subtotal: number
  tax: number
  total: number
}

const calculate: BusinessFunction<CalculateInput, CalculateOutput> = {
  // ...
}

// ❌ Avoid: Implicit any
const calculate: BusinessFunction = {
  // Input and output are 'any'
}

2. Leverage Type Inference

Let TypeScript infer types when possible:

// ✅ Good: Let TypeScript infer
const workflow = {
  id: 'process-order',
  name: 'Process Order',
  steps: [
    /* ... */
  ],
} satisfies BusinessWorkflow

// ❌ Unnecessary: Manual typing when not needed
const workflow: BusinessWorkflow = {
  id: 'process-order',
  name: 'Process Order',
  steps: [
    /* ... */
  ] as WorkflowStep[],
}

3. Use Type Guards

Create type guards for runtime type checking:

// ✅ Good: Type guard for safety
function assertBusinessFunction(value: unknown): asserts value is BusinessFunction {
  if (!isBusinessFunction(value)) {
    throw new Error('Value is not a BusinessFunction')
  }
}

// Usage
const fn = await loadFunction()
assertBusinessFunction(fn)
await fn.execute(input) // Safe to use

4. Document Complex Types

Add JSDoc comments for complex types:

/**
 * Configuration for a retryable business function
 * @property retries - Maximum number of retry attempts (default: 3)
 * @property retryDelay - Milliseconds to wait between retries (default: 1000)
 * @property backoff - Exponential backoff multiplier (default: 2)
 */
interface RetryConfig {
  retries?: number
  retryDelay?: number
  backoff?: number
}

Next Steps

See Also