m05-type-driven

Encode invariants in types using type-state, phantom types, and newtypes.

Updated Aug 23, 2026
One-click install
npx skills add https://github.com/mberetvas/dbt-migrator --skill m05-type-driven-mberetvas
Or copy as Structured Prompt for Agent
Please help me install this Agent Skill.
Skill: m05-type-driven
Source: https://github.com/mberetvas/dbt-migrator/tree/main/.github/skills/m05-type-driven
Command: npx skills add https://github.com/mberetvas/dbt-migrator --skill m05-type-driven-mberetvas

SYSTEM DOCUMENTATION & REQUIREMENTS

What problem does it solve?

This skill helps engineers prevent invalid states by moving invariants from runtime checks into the type system and compile-time guarantees.

Core Features & Use Cases

  • Type-state patterns to encode transitions at compile time and ensure correct API usage.
  • Newtypes, phantom types, and marker traits to represent domain concepts safely.
  • Builder patterns and validated constructors to progressively construct complex objects and seal invariants.
  • Guidance on when to validate at construction versus state transitions, and how to leverage compile-time checks for safer APIs.

Quick Start

Create a typed wrapper for the primitive and expose a validated constructor to enforce invariants before use.

Frequently Asked Questions about m05-type-driven

High-intent search queries and answers about installing and using this skill.

FAQPage Schema
How do I enforce compile-time invariants to prevent invalid states in Rust?

You can enforce compile-time invariants by encoding invalid states as impossible using type-driven design. This approach leverages type-level patterns like type state and marker traits to catch errors during compilation rather than at runtime.

What is the typestate pattern and how does it ensure safer APIs?

The typestate pattern encodes state transitions directly into the type system, ensuring safer APIs by making invalid API usage a compile-time error. It restricts operations to valid states, preventing unauthorized transitions before execution.

When should I use phantom types and newtypes for domain concepts?

Use phantom types and newtypes to represent domain concepts safely when you need to distinguish data at the type level without runtime overhead. They provide zero-cost type safety by tagging data with compile-time distinctions.

What's the best way to progressively construct complex objects while sealing invariants?

The best way to progressively construct complex objects is by using builder patterns alongside validated constructors. This ensures invariants are sealed during construction, preventing the creation of partially valid or invalid objects.

When should I validate data at construction versus during state transitions?

Validate data at construction to guarantee an object is never instantiated in an invalid state, and validate during state transitions to enforce lifecycle rules. Type-driven design helps determine the optimal checkpoint for compile-time checks.

Can I use type-driven design patterns across languages other than Rust?

Yes, type-driven design patterns apply across languages that support generics and type systems. While Rust excels at zero-cost abstractions, you can implement newtypes, phantom types, and builders in any statically typed language for safer APIs.