-
Notifications
You must be signed in to change notification settings - Fork 9
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
abort()
method absent on promises returned by mw.Api
#50
Comments
And I guess you need to export this type somehow. Maybe add it to type Promise<T extends ApiResponse = ApiResponse> = JQuery.Promise<T> & Pick<JQuery.jqXHR, 'abort'>; so that it becomes There is the same story with the REST API, https://github.com/wikimedia/mediawiki/blob/master/resources/src/mediawiki.api/rest.js. So you might have type Promise<T extends RestResponse = RestResponse> = JQuery.Promise<T> & Pick<JQuery.jqXHR, 'abort'>; |
Sounds good to me. Some API methods only return a specific field from the response object (e.g. type Promise<T = ApiResponse> = JQuery.Promise<T> & Pick<JQuery.jqXHR, 'abort'>; |
While we're on it, I suggest we also add types for the other response promise parameters. (result: ApiResponse, jqXHR: JQuery.jqXHR<ApiResponse>) and on error all methods fail with (code: string, data: any, result: any, jqXHR: JQuery.jqXHR) With type Promise<T, U = never> = JQuery.PromiseBase<T, string, never,
U, any, never,
never, any, never,
never, JQuery.jqXHR, never> & Pick<JQuery.jqXHR, 'abort'>; and get(...): Api.Promise<ApiResponse, JQuery.jqXHR<ApiResponse>>;
getToken(...): Api.Promise<string>;
... Note that the 4th type parameter of |
As opposed to the resolving callback, rejection callbacks are trickier actually. There are 2 signatures (actually 3 if you count one that has |
So the 1st error parameter is always a
Based on the above promise type: interface HttpErrorData {
exception: string;
textStatus: JQuery.Ajax.ErrorTextStatus;
xhr: JQuery.jqXHR;
}
type EmptyResponseMessage = 'OK response but empty result (check HTTP headers?)';
type Promise<T = any, U = never, V = never, S = never>
= JQuery.PromiseBase<T, string, never,
U, HttpErrorData | EmptyResponseMessage | ApiResponse, never,
V, ApiResponse | '' | null | undefined, never,
S, JQuery.jqXHR<ApiResponse | '' | null | undefined> | undefined, never>
& Pick<JQuery.jqXHR, 'abort'>; |
Some specific API methods provide different arguments on error (e.g. interface HttpErrorData<T = any> {
exception: string;
textStatus: JQuery.Ajax.ErrorTextStatus;
xhr: JQuery.jqXHR<T>;
}
type Promise<R extends Promise.Params = [ApiResponse, JQuery.jqXHR<ApiResponse>], // on success
J extends Promise.Params = Promise.ErrorParams, // on fail
N extends Promise.Params = []> // on notify
= JQuery.PromiseBase<R[0], J[0], N[0],
R[1], J[1], N[1],
R[2], J[2], N[2],
R[3], J[3], N[3]>
& Pick<JQuery.jqXHR, 'abort'>;
namespace Promise {
// JQuery.Promise uses 4 type variables T, U, V, and S.
// Callbacks are typed with `(t: T, u: U, v: V, ...s: S[]) => void`.
type Params = [any?, any?, any?, any?];
// Arguments received by error callbacks when using base API methods.
type ErrorParams =
| ["http", HttpErrorData]
| ["ok-but-empty", "OK response but empty result (check HTTP headers?)", "" | null | undefined, JQuery.jqXHR<"" | null | undefined>]
| [string, ApiResponse, ApiResponse, JQuery.jqXHR<ApiResponse>];
} A typical upload promise could then be specified as: mw.Api.Promise<[ApiResponse], // on success
[string, mw.Api.Promise.ErrorParams[1]], // on fail
[number]> // on notify |
Some further changes to the above proposal:
For the base promise format: namespace Api {
interface PromiseBase<TResolve extends ArgTuple, TReject extends ArgTuple, TNotify extends ArgTuple>
extends JQuery.PromiseBase<Arg<TResolve, 0>, Arg<TReject, 0>, Arg<TNotify, 0>,
Arg<TResolve, 1>, Arg<TReject, 1>, Arg<TNotify, 1>,
Arg<TResolve, 2>, Arg<TReject, 2>, Arg<TNotify, 2>,
Arg<TResolve, 3>, Arg<TReject, 3>, Arg<TNotify, 3>>,
Pick<JQuery.jqXHR, "abort"> {}
type ArgTuple = [any?, any?, any?, any?];
// Extract an argument type from an ArgTuple. Works as following:
// * If T is an empty tuple, argument type is `never`.
// * If the argument to extract is the first one, get its type.
// * Otherwise, remove the head (if it exists) of each array from the type union T
// then (tail-recursively) start over.
type Arg<T extends ArgTuple, N extends number, TAcc extends never[] = []> =
false extends (T extends [] ? true : false)
? TAcc["length"] extends N ? T[0] : Arg<Tail<T>, N, [...TAcc, never]>
: never;
}
type Tail<T extends any[]> = T extends [] ? T : T extends [any?, ...infer R] ? R : T; For namespace Rest {
type Promise<TResolve extends Api.ArgTuple = [RestResponse, JQuery.jqXHR<RestResponse>],
TReject extends Api.ArgTuple = RejectArgTuple,
TNotify extends Api.ArgTuple = []>
= Api.PromiseBase<TResolve, TReject, TNotify>;
type RejectArgTuple =
| ["http", HttpErrorData];
} For namespace Api {
type Promise<TResolve extends ArgTuple = [ApiResponse, JQuery.jqXHR<ApiResponse>],
TReject extends ArgTuple = RejectArgTuple,
TNotify extends ArgTuple = []>
= PromiseBase<TResolve, TReject, TNotify>;
type RejectArgTuple =
| Rest.RejectArgTuple
| ["ok-but-empty", "OK response but empty result (check HTTP headers?)", "" | null | undefined, JQuery.jqXHR<"" | null | undefined>]
| [string, ApiResponse, ApiResponse, JQuery.jqXHR<ApiResponse>];
} Gist from previous comment is updated with that. |
The above implementation is in #51 (I still need to check if that could cause breakage, not sure about that). |
It seems mostly ok, apart from some special cases (listed in the associated PR description). |
`mediawiki.api`: Add custom `Promise` types to fix #50
Requests made with
mw.Api
have something other kinds of promises known to mankind don't have – theabort()
method. It's added using constructions like.promise({ abort: xhr.abort })
in https://github.com/wikimedia/mediawiki/blob/master/resources/src/mediawiki.api/index.js and allows to easily terminate network activity.types-mediawiki
doesn't know about it:I fixed it locally by adding a type
and replacing each and every
JQuery.Promise<ApiResponse>
in https://github.com/wikimedia-gadgets/types-mediawiki/blob/main/mw/Api.d.ts withJQueryPromiseWithAbort<ApiResponse>
.Can't vouch this is perfectly correct – please recheck.
The text was updated successfully, but these errors were encountered: