← Back to Elara
AgentElara

Skill · Version 1.0.0

Type-safe contracts

Strengthens application contracts at untrusted boundaries and represents domain states so invalid combinations are harder to construct.

type-safety-contracts

See how it helps

When is it useful?

Use it when loosely typed objects, nullable fields or runtime assumptions make errors travel deep into business logic.

What does it help you do?

  • Parses untrusted data into validated boundary types.
  • Uses tagged unions to exclude contradictory lifecycle states.
  • Distinguishes missing, empty and unloaded values during gradual tightening.

Try asking this

Replace an ambiguous loading-data-error object with explicit states and boundary parsing. Model initial loading, an empty result and a failed refresh separately. Boundary validation must reject malformed responses before contradictory states reach the renderer.

Detailed documentation

Read the skill’s original instructions, examples and checks in their authored language.

Details…Show less

Type Safety & Contract Improvement

Legacy code often passes untyped dictionaries, any/unknown/mixed payloads, nullable flags and stringly-typed status codes through deep call chains, forcing every function to guess what shape its inputs have or to repeat defensive checks. Strengthening types and contracts turns implicit runtime assumptions into compile-time and boundary-enforced guarantees.

1. Parse, Don't Validate at System Boundaries

Follow Alexis King's principle: validate untrusted external data once at the perimeter and parse it into a precise, trusted internal representation.

  • Identify untrusted boundaries: HTTP request bodies/queries, CLI arguments, environment variables, JSON.parse outputs, database JSON columns, webhook payloads, IPC messages and third-party API responses.
  • Validate at the edge: use the project's established schema validator or boundary parser to check required fields, types, ranges and defaults immediately upon entry, returning a narrow, well-typed value or a structured validation error.
  • Eliminate redundant interior defensive clutter: once core domain functions receive a validated type, they no longer need defensive typeof x === 'string' checks on every line.

2. Make Illegal States Unrepresentable

Replace ambiguous combinations of optional fields and boolean flags with explicit state modeling:

  • Discriminated (Tagged) Unions: instead of { status: string; data?: T; error?: Error; isLoading?: boolean } where isLoading: true and error: Error can coexist accidentally, model mutually exclusive states explicitly:
    • { status: 'idle' } | { status: 'loading' } | { status: 'success'; data: T } | { status: 'error'; error: AppError }.
  • Replace Primitive Obsession at Key Seams:
    • Distinguish domain identifiers (UserId, WorkspaceId, TaskId), units (DurationMs, AmountCents) and constrained enums so arguments cannot be swapped accidentally.
    • Replace magic strings and numeric flags with explicit literal unions, enums or named constants exported from a single source of truth.
  • Explicit Nullability: distinguish clearly between "value not loaded yet", "value intentionally empty (null)" and "field omitted (undefined)".

3. Incremental Type Tightening Without Breaking Callers

Never silence type errors with blanket @ts-ignore, as any or unchecked type assertions that lie to the compiler:

  1. Tighten from the leaves or boundaries inward: start with leaf utilities, data parsers and return types — inferred return types naturally propagate stronger types to callers.
  2. Use function overloads or default type parameters temporarily: when tightening a widely used shared helper, keep backward-compatible call signatures while migrating call sites in batches.
  3. Honest narrowing: when dealing with genuinely dynamic or legacy values (unknown), write small, reusable type guards or assertion helpers that verify the runtime shape before narrowing the type.
  4. Verify runtime parity: remember that static types are erased at runtime in TypeScript/Python/PHP hints; any contract crossing an external I/O boundary must pair static types with runtime validation if the input is not already guaranteed.

Included files 1

  • SKILL.md