Skip to content

feat(merge-props): generic over the consumer's props — cast-free call sites#51

Merged
ivanbanov merged 1 commit into
mainfrom
feat/mergeprops-generics
Jul 19, 2026
Merged

feat(merge-props): generic over the consumer's props — cast-free call sites#51
ivanbanov merged 1 commit into
mainfrom
feat/mergeprops-generics

Conversation

@ivanbanov

Copy link
Copy Markdown
Member

Summary

mergeProps was typed Record<string, unknown> -> Record<string, unknown>, which forces every binding call site into a double cast:

const merged = mergeProps(props as Record<string, unknown>, bindings) as PressableProps
  • cast in — framework prop types are interfaces without index signatures, not assignable to Record<string, unknown>
  • cast out — the anonymous return can't spread onto a typed component

This makes it generic across the base (state-machine-utils) and all three adapters (react / native / opentui):

function mergeProps<Props extends object = Record<string, unknown>>(
  consumer: Props | undefined,
  library: Record<string, unknown>,
): Props & Record<string, unknown>

The return is the Object.assign-style intersection: assignable to the component's props (the JSX spread needs no cast) while the library's bindings stay reachable on the result — pure Props would have hidden them, which the existing tests caught immediately.

// call sites, after
const merged = mergeProps(props, normalize(api.parts.backdrop))
return <Pressable {...merged} />

Type-only; behavior unchanged. Downstream sweep: dunky/ui's react + native dialog bindings drop ~16 casts once this releases.

Test plan

  • pnpm test:ci — 923 tests, 84 files (2 new type-preservation tests via expectTypeOf)
  • pnpm typecheck / pnpm lint / pnpm format:check
  • pnpm build — all packages

🤖 Generated with Claude Code

… sites

mergeProps typed Record<string, unknown> on both ends forced every binding
call site into a double cast: framework prop interfaces (no index signature)
aren't assignable in, and the anonymous return can't spread onto a typed
component. Make it generic (base + react/native/opentui): consumer props
pass in as-is and return as the Object.assign-style intersection
Props & Record<string, unknown> — assignable to the component's props,
library bindings still reachable. Behavior unchanged.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
@vercel

vercel Bot commented Jul 19, 2026

Copy link
Copy Markdown

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
dunky-state-machine Ready Ready Preview, Comment Jul 19, 2026 11:22pm

@ivanbanov
ivanbanov merged commit a37c088 into main Jul 19, 2026
8 checks passed
@ivanbanov
ivanbanov deleted the feat/mergeprops-generics branch July 19, 2026 23:29
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant