mirror of
https://github.com/nuxt/nuxt.git
synced 2025-02-16 13:48:13 +00:00
feat(nuxt3): let useAsyncData()
return value that error
can defined type by generics (#4109)
This commit is contained in:
parent
8284e7fa21
commit
b7dc0931c4
@ -8,7 +8,7 @@ const {
|
|||||||
data: Ref<DataT>,
|
data: Ref<DataT>,
|
||||||
pending: Ref<boolean>,
|
pending: Ref<boolean>,
|
||||||
refresh: () => Promise<void>,
|
refresh: () => Promise<void>,
|
||||||
error?: any
|
error: Ref<any>
|
||||||
} = useAsyncData(
|
} = useAsyncData(
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<Object>,
|
handler: (ctx?: NuxtApp) => Promise<Object>,
|
||||||
|
@ -28,26 +28,27 @@ export interface RefreshOptions {
|
|||||||
_initial?: boolean
|
_initial?: boolean
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface _AsyncData<DataT> {
|
export interface _AsyncData<DataT, ErrorT> {
|
||||||
data: Ref<DataT>
|
data: Ref<DataT>
|
||||||
pending: Ref<boolean>
|
pending: Ref<boolean>
|
||||||
refresh: (opts?: RefreshOptions) => Promise<void>
|
refresh: (opts?: RefreshOptions) => Promise<void>
|
||||||
error?: any
|
error: Ref<ErrorT>
|
||||||
}
|
}
|
||||||
|
|
||||||
export type AsyncData<Data> = _AsyncData<Data> & Promise<_AsyncData<Data>>
|
export type AsyncData<Data, Error> = _AsyncData<Data, Error> & Promise<_AsyncData<Data, Error>>
|
||||||
|
|
||||||
const getDefault = () => null
|
const getDefault = () => null
|
||||||
|
|
||||||
export function useAsyncData<
|
export function useAsyncData<
|
||||||
DataT,
|
DataT,
|
||||||
|
DataE = any,
|
||||||
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
||||||
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
||||||
> (
|
> (
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<DataT>,
|
handler: (ctx?: NuxtApp) => Promise<DataT>,
|
||||||
options: AsyncDataOptions<DataT, Transform, PickKeys> = {}
|
options: AsyncDataOptions<DataT, Transform, PickKeys> = {}
|
||||||
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>> {
|
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE> {
|
||||||
// Validate arguments
|
// Validate arguments
|
||||||
if (typeof key !== 'string') {
|
if (typeof key !== 'string') {
|
||||||
throw new TypeError('asyncData key must be a 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()),
|
data: ref(nuxt.payload.data[key] ?? options.default()),
|
||||||
pending: ref(!useInitialCache()),
|
pending: ref(!useInitialCache()),
|
||||||
error: ref(nuxt.payload._errors[key] ?? null)
|
error: ref(nuxt.payload._errors[key] ?? null)
|
||||||
} as AsyncData<DataT>
|
} as AsyncData<DataT, DataE>
|
||||||
|
|
||||||
asyncData.refresh = (opts = {}) => {
|
asyncData.refresh = (opts = {}) => {
|
||||||
// Avoid fetching same key more than once at a time
|
// Avoid fetching same key more than once at a time
|
||||||
@ -164,21 +165,22 @@ export function useAsyncData<
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Allow directly awaiting on asyncData
|
// Allow directly awaiting on asyncData
|
||||||
const asyncDataPromise = Promise.resolve(nuxt._asyncDataPromises[key]).then(() => asyncData) as AsyncData<DataT>
|
const asyncDataPromise = Promise.resolve(nuxt._asyncDataPromises[key]).then(() => asyncData) as AsyncData<DataT, DataE>
|
||||||
Object.assign(asyncDataPromise, asyncData)
|
Object.assign(asyncDataPromise, asyncData)
|
||||||
|
|
||||||
return asyncDataPromise as AsyncData<PickFrom<ReturnType<Transform>, PickKeys>>
|
return asyncDataPromise as AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE>
|
||||||
}
|
}
|
||||||
|
|
||||||
export function useLazyAsyncData<
|
export function useLazyAsyncData<
|
||||||
DataT,
|
DataT,
|
||||||
|
DataE = any,
|
||||||
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
Transform extends _Transform<DataT> = _Transform<DataT, DataT>,
|
||||||
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
PickKeys extends KeyOfRes<Transform> = KeyOfRes<Transform>
|
||||||
> (
|
> (
|
||||||
key: string,
|
key: string,
|
||||||
handler: (ctx?: NuxtApp) => Promise<DataT>,
|
handler: (ctx?: NuxtApp) => Promise<DataT>,
|
||||||
options: Omit<AsyncDataOptions<DataT, Transform, PickKeys>, 'lazy'> = {}
|
options: Omit<AsyncDataOptions<DataT, Transform, PickKeys>, 'lazy'> = {}
|
||||||
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>> {
|
): AsyncData<PickFrom<ReturnType<Transform>, PickKeys>, DataE> {
|
||||||
return useAsyncData(key, handler, { ...options, lazy: true })
|
return useAsyncData(key, handler, { ...options, lazy: true })
|
||||||
}
|
}
|
||||||
|
|
||||||
|
16
test/fixtures/basic/types.ts
vendored
16
test/fixtures/basic/types.ts
vendored
@ -17,6 +17,22 @@ describe('API routes', () => {
|
|||||||
expectTypeOf($fetch<TestResponse>('/test')).toMatchTypeOf<Promise<TestResponse>>()
|
expectTypeOf($fetch<TestResponse>('/test')).toMatchTypeOf<Promise<TestResponse>>()
|
||||||
})
|
})
|
||||||
|
|
||||||
|
it('works with useAsyncData', () => {
|
||||||
|
expectTypeOf(useAsyncData('api-hello', () => $fetch('/api/hello')).data).toMatchTypeOf<Ref<string>>()
|
||||||
|
expectTypeOf(useAsyncData('api-hey', () => $fetch('/api/hey')).data).toMatchTypeOf<Ref<{ foo:string, baz: string }>>()
|
||||||
|
expectTypeOf(useAsyncData('api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toMatchTypeOf<Ref<{ baz: string }>>()
|
||||||
|
expectTypeOf(useAsyncData('api-other', () => $fetch('/api/other')).data).toMatchTypeOf<Ref<unknown>>()
|
||||||
|
expectTypeOf(useAsyncData<TestResponse>('api-generics', () => $fetch('/test')).data).toMatchTypeOf<Ref<TestResponse>>()
|
||||||
|
expectTypeOf(useAsyncData<any, string>('api-error-generics', () => $fetch('/test')).error).toMatchTypeOf<Ref<string>>()
|
||||||
|
|
||||||
|
expectTypeOf(useLazyAsyncData('lazy-api-hello', () => $fetch('/api/hello')).data).toMatchTypeOf<Ref<string>>()
|
||||||
|
expectTypeOf(useLazyAsyncData('lazy-api-hey', () => $fetch('/api/hey')).data).toMatchTypeOf<Ref<{ foo:string, baz: string }>>()
|
||||||
|
expectTypeOf(useLazyAsyncData('lazy-api-hey-with-pick', () => $fetch('/api/hey'), { pick: ['baz'] }).data).toMatchTypeOf<Ref<{ baz: string }>>()
|
||||||
|
expectTypeOf(useLazyAsyncData('lazy-api-other', () => $fetch('/api/other')).data).toMatchTypeOf<Ref<unknown>>()
|
||||||
|
expectTypeOf(useLazyAsyncData<TestResponse>('lazy-api-generics', () => $fetch('/test')).data).toMatchTypeOf<Ref<TestResponse>>()
|
||||||
|
expectTypeOf(useLazyAsyncData<any, string>('lazy-error-generics', () => $fetch('/test')).error).toMatchTypeOf<Ref<string>>()
|
||||||
|
})
|
||||||
|
|
||||||
it('works with useFetch', () => {
|
it('works with useFetch', () => {
|
||||||
expectTypeOf(useFetch('/api/hello').data).toMatchTypeOf<Ref<string>>()
|
expectTypeOf(useFetch('/api/hello').data).toMatchTypeOf<Ref<string>>()
|
||||||
expectTypeOf(useFetch('/api/hey').data).toMatchTypeOf<Ref<{ foo:string, baz: string }>>()
|
expectTypeOf(useFetch('/api/hey').data).toMatchTypeOf<Ref<{ foo:string, baz: string }>>()
|
||||||
|
Loading…
Reference in New Issue
Block a user