diff --git a/docs/content/3.api/1.composables/use-async-data.md b/docs/content/3.api/1.composables/use-async-data.md index 3ff7969fd5..793099a846 100644 --- a/docs/content/3.api/1.composables/use-async-data.md +++ b/docs/content/3.api/1.composables/use-async-data.md @@ -8,7 +8,7 @@ const { data: Ref, pending: Ref, refresh: () => Promise, - error?: any + error: Ref } = useAsyncData( key: string, handler: (ctx?: NuxtApp) => Promise, diff --git a/packages/nuxt3/src/app/composables/asyncData.ts b/packages/nuxt3/src/app/composables/asyncData.ts index c87891bd5b..d32e691415 100644 --- a/packages/nuxt3/src/app/composables/asyncData.ts +++ b/packages/nuxt3/src/app/composables/asyncData.ts @@ -28,26 +28,27 @@ export interface RefreshOptions { _initial?: boolean } -export interface _AsyncData { +export interface _AsyncData { data: Ref pending: Ref refresh: (opts?: RefreshOptions) => Promise - error?: any + error: Ref } -export type AsyncData = _AsyncData & Promise<_AsyncData> +export type AsyncData = _AsyncData & Promise<_AsyncData> const getDefault = () => null export function useAsyncData< DataT, + DataE = any, Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes > ( key: string, handler: (ctx?: NuxtApp) => Promise, options: AsyncDataOptions = {} -): AsyncData, PickKeys>> { +): AsyncData, PickKeys>, DataE> { // Validate arguments if (typeof key !== 'string') { throw new TypeError('asyncData key must be a string') @@ -87,7 +88,7 @@ export function useAsyncData< data: ref(nuxt.payload.data[key] ?? options.default()), pending: ref(!useInitialCache()), error: ref(nuxt.payload._errors[key] ?? null) - } as AsyncData + } as AsyncData asyncData.refresh = (opts = {}) => { // Avoid fetching same key more than once at a time @@ -164,21 +165,22 @@ export function useAsyncData< } // Allow directly awaiting on asyncData - const asyncDataPromise = Promise.resolve(nuxt._asyncDataPromises[key]).then(() => asyncData) as AsyncData + const asyncDataPromise = Promise.resolve(nuxt._asyncDataPromises[key]).then(() => asyncData) as AsyncData Object.assign(asyncDataPromise, asyncData) - return asyncDataPromise as AsyncData, PickKeys>> + return asyncDataPromise as AsyncData, PickKeys>, DataE> } export function useLazyAsyncData< DataT, + DataE = any, Transform extends _Transform = _Transform, PickKeys extends KeyOfRes = KeyOfRes > ( key: string, handler: (ctx?: NuxtApp) => Promise, options: Omit, 'lazy'> = {} -): AsyncData, PickKeys>> { +): AsyncData, PickKeys>, DataE> { return useAsyncData(key, handler, { ...options, lazy: true }) } diff --git a/test/fixtures/basic/types.ts b/test/fixtures/basic/types.ts index 20561e1231..a1c57b51d8 100644 --- a/test/fixtures/basic/types.ts +++ b/test/fixtures/basic/types.ts @@ -17,6 +17,22 @@ describe('API routes', () => { expectTypeOf($fetch('/test')).toMatchTypeOf>() }) + it('works with useAsyncData', () => { + expectTypeOf(useAsyncData('api-hello', () => $fetch('/api/hello')).data).toMatchTypeOf>() + expectTypeOf(useAsyncData('api-hey', () => $fetch('/api/hey')).data).toMatchTypeOf>() + expectTypeOf(useAsyncData('api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toMatchTypeOf>() + expectTypeOf(useAsyncData('api-other', () => $fetch('/api/other')).data).toMatchTypeOf>() + expectTypeOf(useAsyncData('api-generics', () => $fetch('/test')).data).toMatchTypeOf>() + expectTypeOf(useAsyncData('api-error-generics', () => $fetch('/test')).error).toMatchTypeOf>() + + expectTypeOf(useLazyAsyncData('lazy-api-hello', () => $fetch('/api/hello')).data).toMatchTypeOf>() + expectTypeOf(useLazyAsyncData('lazy-api-hey', () => $fetch('/api/hey')).data).toMatchTypeOf>() + expectTypeOf(useLazyAsyncData('lazy-api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toMatchTypeOf>() + expectTypeOf(useLazyAsyncData('lazy-api-other', () => $fetch('/api/other')).data).toMatchTypeOf>() + expectTypeOf(useLazyAsyncData('lazy-api-generics', () => $fetch('/test')).data).toMatchTypeOf>() + expectTypeOf(useLazyAsyncData('lazy-error-generics', () => $fetch('/test')).error).toMatchTypeOf>() + }) + it('works with useFetch', () => { expectTypeOf(useFetch('/api/hello').data).toMatchTypeOf>() expectTypeOf(useFetch('/api/hey').data).toMatchTypeOf>()