Slide 1
The Beachcomber's Guide to Type-Safe Design Systems — Kathleen McMahon — React Alicante 2025
Slide 2
Slide 3
Treasure hunting on the beach
Slide 4
Kathleen wearing a teal rain jacket on a rainy day at the beach.
Slide 5
Sandy path to the beach on a sunny morning.
Slide 6
Random beach drift artwork at sunrise on the beach.
Slide 7
Holding up a clam shell filled with various other shells at sunset by the shoreline.
Slide 8
A trio of clam shells filled with a variety of other shells on the wet sand at sunset.
Slide 9
A tiny sand dollar on the beach, with my foot on the sand to indicate size (shell smaller than my big toe).
Slide 10
A large clam shell half buried in the wet sand at low tide, waves slowly approaching.
Slide 11
A clam shell filled with a group of sand dollars, resting on a wet seaweed-encrusted series of rocks.
Slide 12
Holding up the first sand dollar of the season, sadly broken, with my fingers. Thanks, greenhead fly, for biting me.
Slide 13
A group on sand dollars nestled in a large clam shell on a sand dune in the afternoon.
Slide 14
Did I mention how excited I was to find the sand dollar? And how sad I was that I broke it?
Slide 15
Design Systems = (perfectly) Fragile treasures
Slide 16
Slide 17
The Beachcomber's Guide to Type-Safe Design Systems — Kathleen McMahon — React Alicante 2025
Slide 18
@resource11 Bluesky | Mastodon | Twitter | Instagram | GitHub
Slide 19
Kathleen McMahon — Engineer • Designer • Speaker
Slide 20
My cats, Otis and Thor, sitting on the windowsill next to some moon shells on a warm spring afternoon.
Slide 21
Design Systems are ALWAYS the hotness
A person wearing an inflatable T-rex costume joyfully does a forward flip off a dock into an inflatable raft floating in a pond.
Slide 22
Design systems are like herding kittens
A person attempting to line up a group of 10 wiggly kittens in a line. She was not successful.
Slide 23
O’Reilly — LaunchDarkly — Northwestern Mutual — Electronic Arts
Slide 24
Yes, I’m still sad about that broken sand dollar. Yet it reminds me of the fragility of design systems.
Slide 25
Drift & Fragile Sand Dollars
Slide 26
Drift & Fragile Sand Dollars
Hard-coded
export type ThemeValues = | “katMeow” | “katPurr” | “katSqueak”;
—
Dynamically-generated
// This file is auto-generated
// Do not edit manually
export const THEME_VALUES = [ “katMeow”, “katPurr”, “katSqueak”, “katHiss” ] as const;
export type Theme = typeof THEME_VALUES[number];
Slide 27
Tokens are Design Decisions
Slide 28
Typed Tokens Catch Bugs Early
Slide 29
Typed Tokens Catch Bugs Early
Untyped
margin: var(—space-lgge);
—
Typed
margin: ${theme.space.lg};
Slide 30
When to Invest in Typed Tokens
Slide 31
✅ Multi-app / multi-brand systems
✅ Accessibility / mission-critical
❌ MVPs / chaotic tokens (start clean first)
Slide 32
Type Safety depends on Tooling
Slide 33
Type Safety depends on Tooling
Tailwind → Typed config
PostCSS, SCSS → Style Dictionary pipeline
Vanila CSS → .d.ts exports
Styled Components → Strong TypeScript support
Slide 34
Slide 35
From Fragile to Typed
Before
color: #0044cc;
margin: 12px;
—
After
color: ${theme.color.blue.primary};
margin: ${theme.space.md};
—
No drift → compiler enforces alignment
Slide 36
Tokens workflow — One source of truth, many outputs
Slide 37
Tokens workflow — One source of truth, many outputs
Designers → Figma → Tokens Studio
JSON → Style Dictionary → CSS + TypeScript
Styling + typing aligned
Slide 38
Typed Tokens Catch
Misspelled keys
Invalid overrides
Low-contrast colors
Slide 39
Typed Tokens Catch
Misspelled keys
Without Types
Silent Fail
Misspelled keys
With Types
Compile
Invalid overrides
Without Types
Wrong render
Invalid overrides
With Types
Blocked
Low-contrast colors
Without Types
Missed in QA
Low-contrast colors
With Types
Flagged
Slide 40
Slide 41
Interfaces → shapes (extendable, generic)
Slide 42
Types → Options (exclusive, variant-driven)
Slide 43
Slide 44
Card & Alert in practice
Card: predictable shape → Interface
interface CardProps { title: string; children: React.ReactNode }
—
Alert: variant logic → Type
type AlertProps = { variant: “error” |… }
Slide 45
Why some teams ban interface
Slide 46
📏 Linting Rules: Type Only
• type is more general
• Avoids declaration merging
• Reduces decision fatigue
Slide 47
⚖ Intent matters Interfaces for shape, Types for options
Slide 48
A tiny sand dollar on the beach, with my foot on the sand to indicate size (shell smaller than my big toe).
Slide 49
Blending Interface + Types: MediaCard
• Shared props: title, description (interface)
• Variant props: svg or photo (type union)
• Combined: BaseMediaCardProps & VariantMediaCardProps
Slide 50
Drift Appears When APIs get fuzzy
• Dev adds both svg + photoUrl
• Dev adds aria-label to a photo
• Docs skipped → misuse slips in
Slide 51
Guardrails Using never to Forbid Props
type VariantMediaCardProps =
| {
mediaType:”svg”;
svg:ReactNode;
“aria-label”:string;
photoUrl?:never; alt?:never
} | {
mediaType:”photo”;
photoUrl:string;
alt:string;
svg?:never;
“aria-label”?:never
}
Slide 52
Guardrails Using never to Forbid Props
• Forbids invalid combinations
• Enforces correct accessibility attributes
Slide 53
Slide 54
🚫 Good grief… No!
<Button as=”a”>Link</Button>
<Link variant=”button”>About</Link>
Slide 55
A fish and fruit jello mold resting on a plate. Gross.
Slide 56
🚫 Good grief… No!
<Button as=”a”>Link</Button>
<Link variant=”button”>About</Link>
Slide 57
Slide 58
Slide 59
Successfully makes a jello-fish reference in presentation.
Slide 60
Being a developer is not stressing at all: Kathleen — every day
An older man smiles at the camera. The caption indicates the man is actually 26 years old
Slide 61
⚠ Polymorphic components Flexibility or fragility?
Slide 62
<Button as=”a”>Link</Button>
Slide 63
NO! No, no, no…
❌<Button as=”a”>Link</Button>
❌ <Link variant=”button”>About</Link>
Slide 64
Do this. Please.
✅ <Button>Click me</Button>
✅ <Link StyledAsButton />
✅ <a className=“btn”>Learn more</a>
Slide 65
A button should be a button
Slide 66
Slide 67
A button should be a button
(say it with me)
Slide 68
Slide 69
🟦 Compile time beats runtime
• Runtime: QA → Jira → patch → deploy
• Compile-time: red squiggle → fixed pre-commit
• Guardrails stop drift earlier
Slide 70
Sharing types is scalable
• Publish once, every app consumes
• No local drift
• Everyone aligned with latest design system
Slide 71
🐚 Wrap-up
• Tokens prevent drift
• Props prevent misuse
• Compile-time confidence scales
Slide 72
A clam shell filled with a group of sand dollars, resting on a wet seaweed-encrusted series of rocks.
Slide 73
🐚 Beachcomb your design system.
Slide 74
Slide 75
Slide 76
@resource11 Twitter | Instagram | GitHub
Slide 77
Still. Sad about that broken sand dollar.
Slide 78
Otis, the sleek black cat of wonder, playfully interrupts the sand dollar arrangement on my table.