Skip to content

UseGenerationReturn discards TInput: generate is typed (input: Record<string, any>) #1003

Description

@jherr

Found while reviewing the @tanstack/ai-octane port (#1000). Fixed there; filing so the other adapters can catch up.

Problem

useGeneration takes a TInput extends Record<string, any> type parameter, and its internal generate really is (input: TInput) => Promise<void>. But the exported return type throws that away:

export interface UseGenerationReturn<TOutput> {
  generate: (input: Record<string, any>) => Promise<void>
  // ...
}

and the implementation casts to match:

return {
  generate: generate as (input: Record<string, any>) => Promise<void>,
  // ...
}

So required and narrow input fields are unchecked at the call site. With useGeneration<{ prompt: string; steps: number }, R>, all of these compile:

generate({ prompt: 'x' })                      // missing `steps`
generate({ prompt: 'x', steps: 'four' })       // wrong type
generate({ prompt: 'x', steps: 4, seed: 1 })   // unknown key

Fix

Parameterize the return type with TInput and drop the cast:

-export interface UseGenerationReturn<TOutput> {
-  generate: (input: Record<string, any>) => Promise<void>
+export interface UseGenerationReturn<TInput, TOutput> {
+  generate: (input: TInput) => Promise<void>
-): UseGenerationReturn<InferGenerationOutputFromReturn<TResult, TTransformed>> {
+): UseGenerationReturn<
+  TInput,
+  InferGenerationOutputFromReturn<TResult, TTransformed>
+> {
 return {
-  generate: generate as (input: Record<string, any>) => Promise<void>,
+  generate,

In ai-octane this needed no other changes — the media hooks (useGenerateImage/Audio/Speech/Video) declare their own return types and don't reference UseGenerationReturn.

Caveat

This changes the arity of an exported type, so it's breaking for anyone who writes UseGenerationReturn<T> explicitly. Worth batching into a release that's already taking a version bump. ai-octane could absorb it freely (unpublished at 0.0.0), which is why it diverges today — see packages/ai-octane/status.json.

Test

packages/ai-octane/typetests/use-generation.test-d.ts locks this in with @ts-expect-error cases for each of the three bad calls above; verified to fail if the widening is reintroduced.

Affected

  • @tanstack/ai-react
  • @tanstack/ai-vue
  • @tanstack/ai-solid

(@tanstack/ai-octane fixed in #1000.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions