@data-client/endpoint
Version:
Declarative Network Interface Definitions
201 lines (176 loc) • 6.03 kB
text/typescript
/* eslint-disable @typescript-eslint/no-unsafe-function-type */
import type { EndpointInterface, Schema } from './interface.js';
import type {
EndpointExtraOptions,
FetchFunction,
PartialParameters,
} from './types.js';
export interface EndpointOptions<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = undefined,
M extends boolean | undefined = false,
> extends EndpointExtraOptions<F> {
key?: (...args: Parameters<F>) => string;
sideEffect?: M;
schema?: S;
[k: string]: any;
}
export interface EndpointExtendOptions<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends boolean | undefined = boolean | undefined,
> extends EndpointOptions<F, S, M> {
fetch?: FetchFunction;
}
export type ParamFromFetch<F> =
F extends (params: infer P, body?: any) => Promise<any> ? P : never;
//type Overwrite<T, U> = Pick<T, Exclude<keyof T, keyof U>> & U; TODO: should we use this?
export type KeyofEndpointInstance = keyof EndpointInstance<FetchFunction>;
export type ExtendedEndpoint<
O extends EndpointExtendOptions<F>,
E extends EndpointInstance<
FetchFunction,
Schema | undefined,
boolean | undefined
>,
F extends FetchFunction,
> = EndpointInstance<
'fetch' extends keyof O ? Exclude<O['fetch'], undefined> : E['fetch'],
'schema' extends keyof O ? O['schema'] : E['schema'],
'sideEffect' extends keyof O ? O['sideEffect'] : E['sideEffect']
> &
Omit<O, KeyofEndpointInstance> &
Omit<E, KeyofEndpointInstance>;
/**
* Defines an async data source.
* @see https://dataclient.io/docs/api/Endpoint
*/
export interface EndpointInstance<
F extends (...args: any) => Promise<any> = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends boolean | undefined = boolean | undefined,
> extends EndpointInstanceInterface<F, S, M> {
extend<
E extends EndpointInstance<
(...args: any) => Promise<any>,
Schema | undefined,
boolean | undefined
>,
O extends EndpointExtendOptions<F> &
Partial<Omit<E, keyof EndpointInstance<FetchFunction>>> &
Record<string, unknown>,
>(
this: E,
options: Readonly<O>,
): ExtendedEndpoint<typeof options, E, F>;
}
/**
* Defines an async data source.
* @see https://dataclient.io/docs/api/Endpoint
*/
export interface EndpointInstanceInterface<
F extends FetchFunction = FetchFunction,
S extends Schema | undefined = Schema | undefined,
M extends boolean | undefined = boolean | undefined,
> extends EndpointInterface<F, S, M> {
constructor: EndpointConstructor;
/**
* Calls the function, substituting the specified object for the this value of the function, and the specified array for the arguments of the function.
* @param thisArg The object to be used as the this object.
* @param argArray A set of arguments to be passed to the function.
*/
apply<E extends FetchFunction>(
this: E,
thisArg: ThisParameterType<E>,
argArray?: Parameters<E>,
): ReturnType<E>;
/**
* Calls a method of an object, substituting another object for the current object.
* @param thisArg The object to be used as the current object.
* @param argArray A list of arguments to be passed to the method.
*/
call<E extends FetchFunction>(
this: E,
thisArg: ThisParameterType<E>,
...argArray: Parameters<E>
): ReturnType<E>;
/**
* For a given function, creates a bound function that has the same body as the original function.
* The this object of the bound function is associated with the specified object, and has the specified initial parameters.
* @param thisArg An object to which the this keyword can refer inside the new function.
* @param argArray A list of arguments to be passed to the new function.
*/
bind<E extends FetchFunction, P extends PartialParameters<E>>(
this: E,
thisArg: ThisParameterType<E>,
...args: readonly [...P]
): EndpointInstance<
(...args: readonly [...RemoveArray<Parameters<E>, P>]) => ReturnType<E>,
S,
M
> &
Omit<E, keyof EndpointInstance<FetchFunction>>;
/** Returns a string representation of a function. */
toString(): string;
prototype: any;
readonly length: number;
// Non-standard extensions
arguments: any;
caller: F;
key(...args: Parameters<F>): string;
readonly sideEffect: M;
readonly schema: S;
fetch: F;
/* utilities */
/** @see https://dataclient.io/rest/api/Endpoint#testKey */
testKey(key: string): boolean;
}
export interface EndpointConstructor {
/**
* Defines an async data source.
* @see https://dataclient.io/docs/api/Endpoint
*/
new <
F extends (
this: EndpointInstance<FetchFunction> & E,
params?: any,
body?: any,
) => Promise<any>,
S extends Schema | undefined = undefined,
M extends boolean | undefined = false,
E extends Record<string, any> = {},
>(
fetchFunction: F,
options?: EndpointOptions<F, S, M> & E,
): EndpointInstance<F, S, M> & E;
readonly prototype: Function;
}
export interface ExtendableEndpointConstructor {
/**
* Defines an async data source.
* @see https://dataclient.io/docs/api/Endpoint
*/
new <
F extends (
this: EndpointInstanceInterface<FetchFunction> & E,
params?: any,
body?: any,
) => Promise<any>,
S extends Schema | undefined = undefined,
M extends boolean | undefined = false,
E extends Record<string, any> = {},
>(
RestFetch: F,
options?: Readonly<EndpointOptions<F, S, M>> & E,
): EndpointInstanceInterface<F, S, M> & E;
readonly prototype: Function;
}
type IfAny<T, Y, N> = 0 extends 1 & T ? Y : N;
type IfTypeScriptLooseNull<Y, N> = 1 | undefined extends 1 ? Y : N;
type OnlyFirst<A extends unknown[]> = A extends [] ? [] : [A[0]];
type RemoveArray<Orig extends any[], Rem extends any[]> =
Rem extends [any, ...infer RestRem] ?
Orig extends [any, ...infer RestOrig] ?
RemoveArray<RestOrig, RestRem>
: never
: Orig;