Describe the bug
@tanstack/vue-query 5.104.0 publishes UseMutationReturnType with a default type argument that names MutationResult. MutationResult is not exported. A project that emits declarations (composite: true, which implies declaration) cannot name the inferred return type of an exported wrapper around useMutation.
TypeScript reports:
TS2883: The inferred type of 'useExampleMutation' cannot be named without a reference to 'MutationResult' from '@tanstack/vue-query/build/modern/useMutation'. This is likely not portable. A type annotation is necessary.
@ts-expect-error on the export suppresses TS2883 and is then reported as unused (TS2578). The diagnostic is produced during declaration emit, after TypeScript decides whether the directive was used. @ts-ignore is not a substitute we can use.
5.91.2 still declares the private alias, but the published .d.ts re-exports the function with export { type UseMutationReturnType, useMutation }. That form typechecks. 5.104.0 uses export type UseMutationReturnType<..., TResult = MutationResult<...>> and export declare function useMutation, and declaration emit then has to name MutationResult.
Related, and not the same report:
Your minimal, reproducible example
No hosted sandbox. vue-tsc --build against a composite project is the reproduction. The three files below are complete.
package.json
{
"private": true,
"type": "module",
"dependencies": {
"@tanstack/vue-query": "5.104.0",
"vue": "3.5.43"
},
"devDependencies": {
"typescript": "6.0.3",
"vue-tsc": "3.3.11"
}
}
tsconfig.json
{
"compilerOptions": {
"composite": true,
"module": "esnext",
"moduleResolution": "bundler",
"strict": true,
"target": "esnext",
"skipLibCheck": true
},
"include": ["src"]
}
src/useExampleMutation.ts
import { useMutation } from '@tanstack/vue-query'
export const useExampleMutation = () => {
return useMutation({
mutationFn: async () => 'ok',
})
}
Steps to reproduce
- Install the three files above.
- Run
pnpm exec vue-tsc --build --noEmit --force.
- See
TS2883 on useExampleMutation.
- Repeat with
@tanstack/vue-query 5.91.2. The same command exits 0.
Expected behavior
An exported wrapper around useMutation should typecheck under composite / declaration emit without naming a private type. MutationResult should be exported, or it should not appear as a default type argument on the public UseMutationReturnType.
How often does this bug happen?
Every time
Platform
- OS: macOS
- Browser: not applicable (vue-tsc)
- Version: TypeScript 6.0.3, vue-tsc 3.3.11, Vue 3.5.43
Tanstack Query adapter
vue-query
TanStack Query version
5.104.0 (does not reproduce on 5.91.2)
TypeScript version
6.0.3
Additional context
Annotating the wrapper as UseMutationReturnType<TData, TError, TVariables, unknown> is not assignable to the value useMutation returns, because that value is instantiated with the private fifth type argument. The annotation only typechecks if the consumer copies MutationResult (DistributiveOmit<MutationObserverResult<...>, 'mutate' | 'reset'>). That copy has to stay in sync with an unexported alias.
Describe the bug
@tanstack/vue-query5.104.0 publishesUseMutationReturnTypewith a default type argument that namesMutationResult.MutationResultis not exported. A project that emits declarations (composite: true, which impliesdeclaration) cannot name the inferred return type of an exported wrapper arounduseMutation.TypeScript reports:
@ts-expect-erroron the export suppressesTS2883and is then reported as unused (TS2578). The diagnostic is produced during declaration emit, after TypeScript decides whether the directive was used.@ts-ignoreis not a substitute we can use.5.91.2 still declares the private alias, but the published
.d.tsre-exports the function withexport { type UseMutationReturnType, useMutation }. That form typechecks. 5.104.0 usesexport type UseMutationReturnType<..., TResult = MutationResult<...>>andexport declare function useMutation, and declaration emit then has to nameMutationResult.Related, and not the same report:
TS2883undernodenextfromexperimentalDts.queryOptions()'s real return type is unexported; the public name with the same identifier points at a different, legacy type聽#11042 (open) is the same class of bug forqueryOptions(), not foruseMutation.Your minimal, reproducible example
No hosted sandbox.
vue-tsc --buildagainst acompositeproject is the reproduction. The three files below are complete.package.json{ "private": true, "type": "module", "dependencies": { "@tanstack/vue-query": "5.104.0", "vue": "3.5.43" }, "devDependencies": { "typescript": "6.0.3", "vue-tsc": "3.3.11" } }tsconfig.json{ "compilerOptions": { "composite": true, "module": "esnext", "moduleResolution": "bundler", "strict": true, "target": "esnext", "skipLibCheck": true }, "include": ["src"] }src/useExampleMutation.tsSteps to reproduce
pnpm exec vue-tsc --build --noEmit --force.TS2883onuseExampleMutation.@tanstack/vue-query5.91.2. The same command exits 0.Expected behavior
An exported wrapper around
useMutationshould typecheck undercomposite/ declaration emit without naming a private type.MutationResultshould be exported, or it should not appear as a default type argument on the publicUseMutationReturnType.How often does this bug happen?
Every time
Platform
Tanstack Query adapter
vue-query
TanStack Query version
5.104.0 (does not reproduce on 5.91.2)
TypeScript version
6.0.3
Additional context
Annotating the wrapper as
UseMutationReturnType<TData, TError, TVariables, unknown>is not assignable to the valueuseMutationreturns, because that value is instantiated with the private fifth type argument. The annotation only typechecks if the consumer copiesMutationResult(DistributiveOmit<MutationObserverResult<...>, 'mutate' | 'reset'>). That copy has to stay in sync with an unexported alias.