You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 

95 lines
3.3 KiB

import { createUseFetch } from '#imports'
import type { AsyncData, UseFetchOptions } from '#app'
import type { KeysOf, PickFrom } from '#app/composables/asyncData'
import type { NitroFetchRequest, TypedInternalResponse, AvailableRouterMethod } from 'nitropack/types'
import type { FetchError } from 'ofetch'
import type { Ref } from 'vue'
/** 与 `R.success` / `R.error` 返回结构对齐 */
export type ApiResponse<T = unknown> = {
code: number
message: string
data: T
}
/** 从 Nitro 推断的响应体上剥离一层 `ApiResponse`,得到 `data` 字段类型 */
export type UnwrapApiResponse<T> = T extends ApiResponse<infer D> ? D : T
export function unwrapApiBody<T>(payload: ApiResponse<T>): T {
if (payload.code !== 0) {
throw new Error(payload.message)
}
return payload.data
}
export const request = $fetch.create({})
const httpFetchDefaults = {
retry: 0,
$fetch: request,
transform: unwrapApiBody,
}
const _useHttpFetch = createUseFetch(httpFetchDefaults)
const _useLazyHttpFetch = createUseFetch({
...httpFetchDefaults,
lazy: true,
})
type DefaultMethod<ReqT extends NitroFetchRequest> = 'get' extends AvailableRouterMethod<ReqT>
? 'get'
: AvailableRouterMethod<ReqT>
type HttpFetchOptions<
_ResT,
DataT,
PickKeys extends KeysOf<DataT>,
DefaultT,
ReqT extends NitroFetchRequest,
Method extends AvailableRouterMethod<ReqT>,
> = Omit<UseFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>, 'transform'>
/**
* 带项目默认选项的 `useFetch`,并在类型上将 `data` 视为接口 `{ code, data, message }` 中的内层 `data`。
*
* 说明:Nuxt的 `createUseFetch` 在类型上不会把工厂里的 `transform` 的出参当作 `AsyncData['data']`,
* 因此这里用薄包装修正 `DataT`(见 `UnwrapApiResponse`)。
*/
export function useHttpFetch<
ResT = void,
ErrorT = FetchError,
ReqT extends NitroFetchRequest = NitroFetchRequest,
Method extends AvailableRouterMethod<ReqT> = ResT extends void
? DefaultMethod<ReqT>
: AvailableRouterMethod<ReqT>,
_ResT = ResT extends void ? TypedInternalResponse<ReqT, unknown, Lowercase<Method>> : ResT,
DataT = UnwrapApiResponse<_ResT>,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = undefined,
>(
url: ReqT | Ref<ReqT, ReqT> | (() => ReqT),
opts?: HttpFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
): AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined> {
return _useHttpFetch(url, opts) as AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined>
}
export function useLazyHttpFetch<
ResT = void,
ErrorT = FetchError,
ReqT extends NitroFetchRequest = NitroFetchRequest,
Method extends AvailableRouterMethod<ReqT> = ResT extends void
? DefaultMethod<ReqT>
: AvailableRouterMethod<ReqT>,
_ResT = ResT extends void ? TypedInternalResponse<ReqT, unknown, Lowercase<Method>> : ResT,
DataT = UnwrapApiResponse<_ResT>,
PickKeys extends KeysOf<DataT> = KeysOf<DataT>,
DefaultT = undefined,
>(
url: ReqT | Ref<ReqT, ReqT> | (() => ReqT),
opts?: HttpFetchOptions<_ResT, DataT, PickKeys, DefaultT, ReqT, Method>,
): AsyncData<DefaultT | PickFrom<DataT, PickKeys>, ErrorT | undefined> {
return _useLazyHttpFetch(url, opts) as AsyncData<
DefaultT | PickFrom<DataT, PickKeys>,
ErrorT | undefined
>
}