```tsx
type Props = {
initial?: number;
step?: number;
min?: number;
max?: number;
};
export function Counter({ initial = 0, step = 1, min = -Infinity, max = Infinity }: Props) {
const clamped = Math.min(max, Math.max(min, initial));
const [count, setCount] = useState(clamped);
const inc = () => setCount(c => Math.min(max, c + step));
const dec = () => setCount(c => Math.max(min, c - step));
const reset = () => setCount(clamped);
return (
<div>
<span aria-live="polite">{count}</span>
<button onClick={dec} disabled={count <= min}>-</button>
<button onClick={reset}>Reset</button>
<button onClick={inc} disabled={count >= max}>+</button>
</div>
);
}
```
Why paper-only here: the gitGood sandbox doesn't run React. The reducer is the testable core - extract it as a pure function (`counterReducer`) and the component becomes thin glue. This is also the right architecture for any non-trivial component: pure logic + React shell.
Interview talking points:
- Use the functional updater form (`setCount(c => ...)`) to avoid stale-closure bugs when handlers fire in quick succession.
- `aria-live="polite"` announces count changes to screen readers without interrupting.
- Disabling at boundaries (vs hiding) keeps button positions stable.
The full reference solution in every supported language stays in the editor above - reveal it there once you have had a real attempt.