Now liveThe Skillselion MCP - thousands of ranked skills, loaded into your agent mid-task. No install.Get it →
zhanghandong avatar

M05 Type Driven

  • 800 installs
  • 1.3k repo stars
  • Updated May 24, 2026
  • zhanghandong/rust-skills

This is a copy of m05-type-driven by actionbook - installs and ranking accrue to the original listing.

m05-type-driven is a Claude Code skill that teaches type-driven design patterns—PhantomData, newtypes, sealed traits, and type state—so Rust developers encode business rules the compiler enforces before runtime.

About

m05-type-driven is a Rust-focused Claude Code skill from zhanghandong/rust-skills that applies type-driven design to make invalid states unrepresentable at compile time. The skill walks through when to reach for newtypes, marker traits, builder patterns, zero-sized types, and sealed traits instead of runtime checks, with triggers covering type state, compile-time validation, and related Chinese keyword phrases. It sits in Layer 1: Language Mechanics and reframes common errors as design questions about what the type system can prove. Developers reach for m05-type-driven when refactoring primitives into domain types, hardening APIs against misuse, or encoding lifecycle states in Rust structs and traits.

  • Teaches type state pattern, PhantomData, newtype, marker traits, and builder pattern
  • Transforms primitive obsession and boolean flags into compile-time guarantees
  • Shifts validation from runtime checks to construction and state transitions
  • Includes 3-layer decision framework: encode constraint, timing of validation, audience of invariant
  • Makes invalid states unrepresentable using sealed traits and zero-sized types

M05 Type Driven by the numbers

  • 800 all-time installs (skills.sh)
  • +6 installs in the week ending Jul 28, 2026 (Skillselion tracking)
  • Security screen: MEDIUM risk (skills.sh audit)
  • Data as of Jul 28, 2026 (Skillselion catalog sync)
npx skills add https://github.com/zhanghandong/rust-skills --skill m05-type-driven

Add your badge

Show developers this skill is listed on Skillselion. Paste this into your README.

Listed on Skillselion
Installs800
repo stars1.3k
Security audit3 / 3 scanners passed
Last updatedMay 24, 2026
Repositoryzhanghandong/rust-skills

How do you encode invalid states in Rust types?

Leverage Rust's type system to encode business rules so the compiler prevents invalid states before code ever runs.

Who is it for?

Rust developers hardening domain models and APIs who want compiler-checked invariants instead of scattered runtime guards.

Skip if: Teams needing quick scripting prototypes or greenfield apps where runtime validation and speed of iteration outweigh type modeling.

When should I use this skill?

The user mentions type state, PhantomData, newtype patterns, sealed traits, or making invalid states unrepresentable in Rust.

What you get

Type-state structs, newtype wrappers, sealed trait modules, and compile-time invariant patterns in Rust source.

  • Type-state Rust modules
  • Newtype and sealed-trait API boundaries

By the numbers

  • Triggers on 12+ Rust type-system keywords including PhantomData, newtype, sealed trait, and ZST

Files

SKILL.mdMarkdownGitHub ↗

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:

1. Can the type encode the constraint?

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

2. When is validation possible?

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

3. 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<Connected>
PhantomDataVariance/lifetimePhantomData<&'a T>
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

Related skills

How it compares

Pick m05-type-driven when modeling invariants in Rust types; use general refactoring skills when the goal is syntax cleanup without domain encoding.

FAQ

What is type-driven design in Rust?

m05-type-driven teaches type-driven design in Rust: model domain states and rules in types so the compiler rejects invalid combinations. Patterns include newtypes, type state, PhantomData, marker traits, and sealed traits instead of runtime checks.

When should Rust developers use newtypes over primitives?

m05-type-driven recommends newtypes when primitive obsession hides invariants like IDs, currencies, or lifecycle states. Wrapping primitives in distinct types lets Rust catch mix-ups at compile time without extra runtime validation.

Does m05-type-driven replace all runtime validation?

m05-type-driven prioritizes compile-time invariants for states the type system can represent, but external input still needs parsing and boundary checks. The skill asks whether each error can move from runtime guards into types first.

Is M05 Type Driven safe to install?

skills.sh reports 3 of 3 security scanners passed. Review the Security Audits panel on this page before installing in production.

Productivity & Planningbackendintegrations

This week in AI coding

Five minutes, every Monday - the tools, releases and tactics for developers.

unsubscribe anytime.