alova
Version:
The Request Toolkit For Ultimate Efficiency
325 lines (289 loc) • 10.3 kB
TypeScript
import type { EventManager, FrameworkReadableState, FrameworkState, IsUnknown } from '@alova/shared';
import {
AlovaGenerics,
FetchRequestState,
FrontRequestState,
MergedStatesMap,
Method,
Progress,
ReferingObject,
StatesExport
} from 'alova';
import { ReactHookExportType } from '../stateshook/react';
import { SolidHookExportType } from '../stateshook/solid';
import { SvelteHookExportType } from '../stateshook/svelte';
import { VueHookExportType } from '../stateshook/vue';
import { VueDemiHookExportType } from '../stateshook/vue-demi';
export interface StateMap<T> {
Vue: VueHookExportType<T>;
Solid: SolidHookExportType<T>;
React: ReactHookExportType<T>;
Svelte: SvelteHookExportType<T>;
VueDemi: VueDemiHookExportType<T>;
}
/**
* alova base event
*/
export interface AlovaEvent<AG extends AlovaGenerics, Args extends any[]> {
/**
* params from send function
*/
args: [...Args, ...any[]];
/**
* current method instance
*/
method: Method<AG>;
}
/**
* success event object
*/
export interface AlovaSuccessEvent<AG extends AlovaGenerics, Args extends any[] = any[]> extends AlovaEvent<AG, Args> {
/** Whether data from cache */
fromCache: boolean;
data: AG['Responded'];
}
/** error event object */
export interface AlovaErrorEvent<AG extends AlovaGenerics, Args extends any[]> extends AlovaEvent<AG, Args> {
error: any;
}
/** completion event object */
export interface AlovaCompleteEvent<AG extends AlovaGenerics, Args extends any[]> extends AlovaEvent<AG, Args> {
/** response status */
status: 'success' | 'error';
/** Whether the data from the cache, when the status is error, from cache is always false */
fromCache: boolean;
data?: AG['Responded'];
error?: any;
}
/**
* Define the type in a way that supports React and Vue. Other types will be needed later and then change on this basis.
* Use the characteristics of different libraries as parent classes for judgment
*/
export type ExportedState<Responded, SE extends StatesExport<any>> = SE['name'] extends keyof StateMap<any>
? StateMap<Responded>[SE['name']]['StateExport']
: Responded;
export type ExportedComputed<Responded, SE extends StatesExport<any>> = SE['name'] extends keyof StateMap<any>
? StateMap<Responded>[SE['name']]['ComputedExport']
: Responded;
export type StateUpdater<ExportedStates extends Record<string, any>, SE extends StatesExport> = (newStates: {
[K in keyof ExportedStates]?: ExportedStates[K] extends ExportedState<infer R, SE> | ExportedComputed<infer R, SE>
? R
: ExportedStates[K];
}) => void;
export type AlovaMethodHandler<AG extends AlovaGenerics = any, Args extends any[] = any[]> = (
...args: Args
) => Method<AG>;
export type SuccessHandler<AG extends AlovaGenerics, Args extends any[]> = (event: AlovaSuccessEvent<AG, Args>) => void;
export type ErrorHandler<AG extends AlovaGenerics, Args extends any[]> = (event: AlovaErrorEvent<AG, Args>) => void;
export type CompleteHandler<AG extends AlovaGenerics, Args extends any[]> = (
event: AlovaCompleteEvent<AG, Args>
) => void;
/** common hook configuration */
export interface UseHookConfig<AG extends AlovaGenerics, Args extends any[] = any[]> {
/**
* force request
* @default false
*/
force?: boolean | ((event: AlovaEvent<AG, Args>) => boolean);
/**
* refering object that sharing some value with this object.
*/
__referingObj?: ReferingObject;
/**
* other attributes
*/
[attr: string]: any;
}
export interface AlovaMiddlewareContext<AG extends AlovaGenerics> {
/** current method instance */
method: Method<AG>;
/**
* cache data, only has value when hit cache
*/
cachedResponse: AG['Responded'] | undefined;
/** the config of current use hook */
config: any;
/** abort request */
abort: UseHookExposure['abort'];
}
/** next function of middleware */
export interface MiddlewareNextGuardConfig<AG extends AlovaGenerics, Args extends any[]> {
force?: UseHookConfig<AG, Args>['force'];
method?: Method<AG>;
}
/**
* context parameters of useRequest and useWatcher middleware
*/
export interface AlovaFrontMiddlewareContext<AG extends AlovaGenerics, Args extends any[] = any[]>
extends AlovaMiddlewareContext<AG> {
/** handler to send request */
send: SendHandler<Args, AG['Responded']>;
/** args response processing callback parameters, which are passed in by send of use hooks */
args: [...Args, ...any[]];
/** state proxies set */
proxyStates: FrontRequestState<
FrameworkState<boolean, 'loading'>,
FrameworkState<AG['Responded'], 'data'>,
FrameworkState<Error | undefined, 'error'>,
FrameworkState<Progress, 'downloading'>,
FrameworkState<Progress, 'uploading'>
>;
/**
* custom control the state `loading` and doesn't toggle `loading` internally any more.
* call it with param `false` to cancel controlling.
* @JOU-amjs
* @param control whether to control loading, default is `true`
*/
controlLoading: (control?: boolean) => void;
/**
* pass custom data
*/
[attr: string]: any;
}
/**
* alova useRequest/useWatcher middleware
*/
export interface AlovaFrontMiddleware<AG extends AlovaGenerics, Args extends any[] = any[]> {
(context: AlovaFrontMiddlewareContext<AG, Args>, next: AlovaGuardNext<AG, Args>): any;
}
/**
* the context param of middleware in useFetcher
*/
export interface AlovaFetcherMiddlewareContext<AG extends AlovaGenerics, Args extends any[]>
extends AlovaMiddlewareContext<AG> {
/** fetch data */
fetch<Transformed>(method: Method<AG>, ...args: [...Args, ...any[]]): Promise<Transformed>;
/** args response processing callback parameters, which are passed in by useFetcher’s fetch */
args: [...Args, ...any[]];
/** state proxies set */
proxyStates: FetchRequestState<
FrameworkState<boolean, 'loading'>,
FrameworkState<Error | undefined, 'error'>,
FrameworkState<Progress, 'downloading'>,
FrameworkState<Progress, 'uploading'>
>;
/**
* custom control the state `loading` and doesn't toggle `loading` internally any more.
* call it with param `false` to cancel controlling.
* @JOU-amjs
* @param control whether to control loading, default is `true`
*/
controlLoading: (control?: boolean) => void;
/**
* pass custom data
*/
[attr: string]: any;
}
/**
* alova useFetcher middleware
*/
export interface AlovaFetcherMiddleware<AG extends AlovaGenerics, Args extends any[] = any[]> {
(context: AlovaFetcherMiddlewareContext<AG, Args>, next: AlovaGuardNext<AG, Args>): any;
}
export type ProxyStateGetter<HookExportedStates extends Record<string, any>> = <K extends keyof HookExportedStates>(
key: K
) => HookExportedStates[K] extends ExportedState<infer Data, any>
? FrameworkState<Data, K & string>
: HookExportedStates[K] extends ExportedComputed<infer Data, any>
? FrameworkReadableState<Data, K & string>
: never;
export interface AlovaGuardNext<AG extends AlovaGenerics, Args extends any[]> {
(guardNextConfig?: MiddlewareNextGuardConfig<AG, Args>): Promise<AG['Responded']>;
}
export type SendHandler<Args extends any[], R> = (...args: [...Args, ...any[]]) => Promise<R>;
export interface UseHookExportedState<AG extends AlovaGenerics>
extends FrontRequestState<
ExportedState<boolean, AG['StatesExport']>,
ExportedState<AG['Responded'], AG['StatesExport']>,
ExportedState<Error | undefined, AG['StatesExport']>,
ExportedState<Progress, AG['StatesExport']>,
ExportedState<Progress, AG['StatesExport']>
> {}
export interface UseHookExposure<
AG extends AlovaGenerics = AlovaGenerics,
Args extends any[] = any[],
SelfType = unknown
> extends UseHookExportedState<AG> {
/**
* abort current request
* @returns a promise that resolves when the request is aborted
*/
abort: () => Promise<void>;
/**
* update state manually
* @example
* ```js
* update({
* data: '...',
* loading: true
* });
* ```
*/
update: StateUpdater<UseHookExportedState<AG>, AG['StatesExport']>;
/**
* send request and pass params
*/
send: SendHandler<Args, AG['Responded']>;
/**
* subscribe to the success event
* @param handler the handler to be called when request is successful
*/
onSuccess(handler: SuccessHandler<AG, Args>): IsUnknown<SelfType, this, SelfType>;
/**
* subscribe to the error event
* @param handler the handler to be called when request is failed
*/
onError(handler: ErrorHandler<AG, Args>): IsUnknown<SelfType, this, SelfType>;
/**
* subscribe to the complete event
* @param handler the handler to be called when request is complete
*/
onComplete(handler: CompleteHandler<AG, Args>): IsUnknown<SelfType, this, SelfType>;
/**
* get the original proxy state object, it's a internal api
*/
__proxyState: ProxyStateGetter<UseHookExportedState<AG>>;
/**
* save component refering object, it's a internal api
*/
__referingObj: ReferingObject;
/**
* send and wait for responding with `await`
* this is always used in `nuxt3` and `<suspense>` of `vue3`
* @example
* ```js
* const { loading, data, error } = await useRequest(...);
* const { loading, data, error } = await useWatcher(...);
* ```
*/
then: (onfulfilled: (value: Omit<IsUnknown<SelfType, this, SelfType>, 'then'>) => void) => void;
}
type EnumHookType = 1 | 2 | 3;
export interface Hook<Args extends any[] = any[]> {
/** The method instance of the last request */
m?: Method;
/** Remove states fns */
rf: Record<string | number | symbol, () => void>;
/** Front states */
fs: FrontRequestState<
FrameworkState<boolean, 'loading'>,
FrameworkState<any, 'data'>,
FrameworkState<Error | undefined, 'error'>,
FrameworkState<Progress, 'downloading'>,
FrameworkState<Progress, 'uploading'>
>;
/** event manager */
em: EventManager<{
success: AlovaSuccessEvent<any, Args>;
error: AlovaErrorEvent<any, Args>;
complete: AlovaCompleteEvent<any, Args>;
}>;
/** hookType, useRequest=1, useWatcher=2, useFetcher=3 */
ht: EnumHookType;
/** hook config */
c: UseHookConfig<any, Args>;
/** refering object */
ro: ReferingObject;
/** merged states */
ms: MergedStatesMap;
}