diff --git a/docs/framework/vue/typescript.md b/docs/framework/vue/typescript.md index 7cf70dbc4f..a660e6e4e3 100644 --- a/docs/framework/vue/typescript.md +++ b/docs/framework/vue/typescript.md @@ -68,6 +68,22 @@ if (isSuccess) { [typescript playground](https://www.typescriptlang.org/play?#code/JYWwDg9gTgLgBAbzgVwM4FMCKz1QJ5wC+cAZlBCHAOQACMAhgHaoMDGA1gPQBuOAtAEcc+KgFgAUKEixEcKOnqsYwbuiKlylKr3RUA3BImsIzeEgAm9BgBo4wVAGVkrVulSp1AXjkKlK9AAUaFjCeAEA2lQwbjBUALq2AQCUcJ4AfHAACpr26AB08qgQADaqAQCsSVWGkiRwAfZOLm6oKQgScJ1wlgwSnJydAHoA-BKEEkA) +The `reactive()` wrapper is what makes this work: it flattens the result into +plain values, so `isSuccess` and `data` stay part of the same discriminated +union. Destructuring `useQuery()` directly gives you independent refs, and +TypeScript cannot carry a narrowing from one ref to another — `if (isSuccess.value)` +leaves `data.value` as `Group[] | undefined`. Without `reactive()`, narrow the +value ref itself: + +```tsx +const { data } = useQuery({ queryKey: ['groups'], queryFn: fetchGroups }) + +if (data.value !== undefined) { + data.value + // ^? const data: Group[] +} +``` + [//]: # 'TypeNarrowing' [//]: # 'TypingError' diff --git a/packages/vue-query/src/__tests__/useQuery.test-d.ts b/packages/vue-query/src/__tests__/useQuery.test-d.ts index 7bb8cd8407..5b7cc172b8 100644 --- a/packages/vue-query/src/__tests__/useQuery.test-d.ts +++ b/packages/vue-query/src/__tests__/useQuery.test-d.ts @@ -2,6 +2,7 @@ import { assertType, describe, expectTypeOf, it } from 'vitest' import { computed, reactive, ref } from 'vue-demi' import { queryKey, sleep } from '@tanstack/query-test-utils' import { queryOptions, useQuery } from '..' +import type { Ref } from 'vue-demi' import type { OmitKeyof, UseQueryOptions, UseQueryReturnType } from '..' describe('useQuery', () => { @@ -289,6 +290,31 @@ describe('useQuery', () => { expectTypeOf(query.error).toEqualTypeOf() } }) + + it('data should be a union of refs without reactive()', () => { + const key = queryKey() + + const query = useQuery({ + queryKey: key, + queryFn: () => sleep(0).then(() => 'Some data'), + }) + + expectTypeOf(query.data).toEqualTypeOf | Ref>() + }) + + it('data.value should narrow on an undefined check without reactive()', () => { + const key = queryKey() + + const { data } = useQuery({ + queryKey: key, + queryFn: () => sleep(0).then(() => 'Some data'), + }) + + if (data.value !== undefined) { + expectTypeOf(data.value).toEqualTypeOf() + expectTypeOf(data).toEqualTypeOf>() + } + }) }) describe('accept ref options', () => {