Best practice L2 · Context engineering informational

Give Claude the Types Before the Logic

What it is

A code-generation pattern where you (or Claude, with your approval) fix the types and function signatures first — the data shapes, inputs, and return types — and only then ask for the implementation that satisfies them.

types firstDefine types /signatureAgree the shapeGenerate implCompiler checks it
Pin the shape, then the behaviour has nowhere to drift.

Why it works

Types are a compact, checkable specification. When the shape is pinned first, the implementation has a target it can't silently drift from, the compiler becomes a second reviewer, and you catch a wrong mental model at the cheapest possible moment — before any logic exists. It also shrinks the prompt: 'implement this signature' is far less ambiguous than 'write a function that does X'.

When to use it

Typed languages and any non-trivial function where the data shape matters — transformations, parsers, API boundaries, state machines. Great when you know the interface but not the internals.

When not to use it

Exploratory prototyping where you're still discovering the shape, or dynamically-typed throwaways. Don't front-load ceremony when you're still figuring out what you want.

Prompt

First, propose the types and function signatures for <feature> — inputs, outputs, and any domain types. Don't implement yet; show me the shapes and a one-line note on each.

After I approve, implement each function to satisfy those types exactly. If an implementation needs a type we didn't define, stop and propose it rather than using `any`.

Example

For an availability calendar you agree on type Slot = { start: ISODate; end: ISODate; booked: boolean } and mergeAvailability(a: Slot[], b: Slot[]): Slot[] first — so the generated merge logic can't quietly return overlapping slots without the compiler complaining.

Advanced version

Ask Claude to make illegal states unrepresentable in the types — a discriminated union instead of a bag of optional fields — so whole classes of bug become compile errors rather than runtime surprises.

Common mistakes

  • Letting any or loose types creep in, which throws away the whole benefit.
  • Approving signatures you haven't actually read, so the wrong shape is now the spec.
  • Over-modelling a throwaway until the type gymnastics cost more than the feature.

Related