Skip to content

useObjectChat's returned setMessages is typed (messages: unknown[]) to void — contravariantly incompatible with the SDK's, and only the chatResult as any at :683 hides it #8342

Description

@os-justin

Found while widening AnyPart.state for objectui#8214. Filed unassigned and NOT fixed there — that card's ruling is a local widening in mapMessages.ts and explicitly says not to widen the PR to chase whatever the second cast is hiding.

Filed by the objectui#8214 dev, Claude Code session session_01YBWFb5YgMU5dw8p2VKj16S. (Attribution is stated here in prose: the trailing rule-line footer block was stripped from this body by the platform on creation, so it is not a durable place to put it.)

Spelling note: generic type arguments are written as WORDS below, because GitHub's body sanitizer eats tag-shaped fragments, backticks and fences included.

What

packages/plugin-chatbot/src/useObjectChat.ts:683 destructures the useChat() result through chatResult as any. objectui#8214 named that cast load-bearing and asked what it is actually holding up. Measured: with objectui#8214's widen applied, removing the cast leaves exactly one diagnostic, and it is not about the mapper at all.

src/useObjectChat.ts(803,7): error TS2322: Type '(messages: UIMessage of unknown, UIDataTypes, UITools array
 | ((messages: UIMessage array) to UIMessage array)) to void' is not assignable to type
 '(messages: unknown[]) to void'.
  Types of parameters 'messages' and 'messages' are incompatible.
    Type 'unknown[]' is not assignable to type 'UIMessage array | ((messages: UIMessage array) to UIMessage array)'.
      Type 'unknown' is not assignable to type 'UIMessage of unknown, UIDataTypes, UITools'.

(Arrow spelled as the word "to" above for the same sanitizer reason.)

The hook returns setMessages declared as taking messages: unknown[]. Parameters are contravariant, so a function that accepts only UIMessage[] is not assignable to one advertised as accepting any unknown[]. The declared type promises callers something the underlying function cannot do.

Reachability

No runtime effect today: the value passed through is the SDK's own setMessages and every in-repo caller happens to hand it real messages. The cost is the same shape objectui#8214 was graded on — the published surface tells a consumer they may pass an arbitrary unknown[], and the only reason nothing breaks is that nobody has taken the type at its word. A consumer who does gets a runtime failure the compiler said was fine.

Measured

  • Base commit: dacb98f3b plus objectui#8214's widen (PR fix(plugin-chatbot): accept the AI SDK's UIMessage in the exported mappers #8341).
  • Instrument: pnpm --filter @object-ui/plugin-chatbot type-check (tsc --noEmit && tsc -p tsconfig.test.json). Vitest cannot see this — it transpiles types away.
  • With the cast in place: exit 0. With } = chatResult as any; changed to } = chatResult;: exit 2, one diagnostic, the TS2322 above. The mutation was proved on disk and restored by state (git diff HEAD empty, git hash-object equal to git rev-parse HEAD:PATH again).

Options, not a ruling

  • A. Type the hook's returned setMessages against what it actually is (the SDK's signature, or a narrowed alias the package owns), and drop the cast. Strictest; ties one more return member to the pinned @ai-sdk/react version, which is the same decision objectui#8214 deliberately declined to make on its parameter type. Probably wants the same eye.
  • B. Keep the returned member deliberately loose but make it honest — accept unknown[] and validate/narrow inside the hook before handing it to the SDK, so the promise on the surface is one the implementation actually keeps.
  • C. Leave the cast and document it. Rejected by the same rule that rejected it on objectui#8214 (AGENTS.md #0.1): a documented cast fossilizes the wrong shape.

Whoever takes this should re-measure before acting — the diagnostic count is measured on top of PR #8341 and may read differently once that lands or if the SDK moves.

Related: objectui#8214 (where the cast was named and this half was deliberately left alone), objectui#4424 (the previous cast removed from this same hook's return path), objectui#4399.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

Labels

bugSomething isn't workingdomain:uiobjectui ui stream: fix lands on the published library or apps — objectui execution seatpluginpm:dispatchedpriority:p2

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions