m05-type-driven

Compile-time state validation through type encoding, eliminating invalid states at the type level. Covers six core patterns: newtype for type-safe primitives, type state for state machines, PhantomData for variance tracking, marker traits for capability flags, builders for gradual construction, and sealed traits for closed impl sets Emphasizes asking "can the compiler catch this?" before adding runtime validation, with decision guides mapping common needs to appropriate patterns Includes anti-patterns section contrasting runtime approaches (boolean flags, string semantics, public fields) with type-driven alternatives Provides trace-up and trace-down navigation to related skills for domain modeling, trait design, and error handling

INSTALLATION
npx skills add https://github.com/zhanghandong/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

Pattern

Don't Just Say

Ask 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)

Situation

Trace To

Question

What types to create

m09-domain

What's the domain model?

State machine design

m09-domain

What are valid transitions?

Marker trait usage

m04-zero-cost

Static 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

Pattern

Purpose

Example

Newtype

Type safety

struct UserId(u64);

Type State

State machine

Connection<Connected>

PhantomData

Variance/lifetime

PhantomData<&#x26;'a T>

Marker Trait

Capability flag

trait Validated {}

Builder

Gradual construction

Builder::new().name("x").build()

Sealed Trait

Prevent external impl

mod private { pub trait Sealed {} }

Pattern Examples

Newtype

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

impl Email {

    pub fn new(s: &#x26;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

Need

Pattern

Type safety for primitives

Newtype

Compile-time state validation

Type State

Lifetime/variance markers

PhantomData

Capability flags

Marker Trait

Gradual construction

Builder

Closed set of impls

Sealed Trait

Zero-sized type marker

ZST struct

Anti-Patterns

Anti-Pattern

Why Bad

Better

Boolean flags for states

Runtime errors

Type state

String for semantic types

No type safety

Newtype

Option for uninitialized

Unclear invariant

Builder

Public fields with invariants

Invariant violation

Private + validated new()

Related Skills

When

See

Domain modeling

m09-domain

Trait design

m04-zero-cost

Error handling in constructors

m06-error-handling

Anti-patterns

m15-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