m05-type-driven

CRITICAL: Use for type-driven design. Triggers: type state, PhantomData, newtype, marker trait, builder pattern, make invalid states unrepresentable,…

INSTALLATION
npx skills add https://github.com/actionbook/rust-skills --skill m05-type-driven
Run in your project or agent environment. Adjust flags if your CLI version differs.

SKILL.md

Type-Driven Design

Layer 1: Language Mechanics

Core Question

How can the type system prevent invalid states?

Before reaching for runtime checks:

  • Can the compiler catch this error?
  • Can invalid states be unrepresentable?
  • Can the type encode the invariant?

Error → Design Question

PatternDon't Just SayAsk Instead
Primitive obsession"It's just a string"What does this value represent?
Boolean flags"Add an is_valid flag"Can states be types?
Optional everywhere"Check for None"Is absence really possible?
Validation at runtime"Return Err if invalid"Can we validate at construction?

Thinking Prompt

Before adding runtime validation:

-

Can the type encode the constraint?

  • Numeric range → bounded types or newtypes
  • Valid states → type state pattern
  • Semantic meaning → newtype

-

When is validation possible?

  • At construction → validated newtype
  • At state transition → type state
  • Only at runtime → Result with clear error

-

Who needs to know the invariant?

  • Compiler → type-level encoding
  • API users → clear type signatures
  • Runtime only → documentation

Trace Up ↑

When type design is unclear:

"Need to validate email format"

    ↑ Ask: Is this a domain value object?

    ↑ Check: m09-domain (Email as Value Object)

    ↑ Check: domain-* (validation requirements)
SituationTrace ToQuestion
What types to createm09-domainWhat's the domain model?
State machine designm09-domainWhat are valid transitions?
Marker trait usagem04-zero-costStatic or dynamic dispatch?

Trace Down ↓

From design to implementation:

"Need type-safe wrapper for primitives"

    ↓ Newtype: struct UserId(u64);

"Need compile-time state validation"

    ↓ Type State: Connection<Connected>

"Need to track phantom type parameters"

    ↓ PhantomData: PhantomData<T>

"Need capability markers"

    ↓ Marker Trait: trait Validated {}

"Need gradual construction"

    ↓ Builder: Builder::new().field(x).build()

Quick Reference

PatternPurposeExample
NewtypeType safetystruct UserId(u64);
Type StateState machineConnection
PhantomDataVariance/lifetimePhantomData
Marker TraitCapability flagtrait Validated {}
BuilderGradual constructionBuilder::new().name("x").build()
Sealed TraitPrevent external implmod private { pub trait Sealed {} }

Pattern Examples

Newtype

struct Email(String);  // Not just any string

impl Email {

    pub fn new(s: &str) -> Result<Self, ValidationError> {

        // Validate once, trust forever

        validate_email(s)?;

        Ok(Self(s.to_string()))

    }

}

Type State

struct Connection<State>(TcpStream, PhantomData<State>);

struct Disconnected;

struct Connected;

struct Authenticated;

impl Connection<Disconnected> {

    fn connect(self) -> Connection<Connected> { ... }

}

impl Connection<Connected> {

    fn authenticate(self) -> Connection<Authenticated> { ... }

}

Decision Guide

NeedPattern
Type safety for primitivesNewtype
Compile-time state validationType State
Lifetime/variance markersPhantomData
Capability flagsMarker Trait
Gradual constructionBuilder
Closed set of implsSealed Trait
Zero-sized type markerZST struct

Anti-Patterns

Anti-PatternWhy BadBetter
Boolean flags for statesRuntime errorsType state
String for semantic typesNo type safetyNewtype
Option for uninitializedUnclear invariantBuilder
Public fields with invariantsInvariant violationPrivate + validated new()

Related Skills

WhenSee
Domain modelingm09-domain
Trait designm04-zero-cost
Error handling in constructorsm06-error-handling
Anti-patternsm15-anti-pattern
BrowserAct

Let your agent run on any real-world website

Bypass CAPTCHA & anti-bot for free. Start local, scale to cloud.

Explore BrowserAct Skills →

Stop writing automation&scrapers

Install the CLI. Run your first Skill in 30 seconds. Scale when you're ready.

Start free
free · no credit card