fix: improve TypeScript types (#841)
* fix: improve TypeScript types * fix: disable allowSyntheticDefaultImports and esModuleInterop * fix: improve HeadersInit types (js/ts) * fix: fully match types to build index.cjs * fix: allow Iterable<Iterable<string>> in HeadersInit
This commit is contained in:
parent
769f75d054
commit
e6bfe4d419
|
@ -3,10 +3,16 @@
|
|||
/* eslint-disable no-var, import/no-mutable-exports */
|
||||
|
||||
import {Agent} from 'http';
|
||||
import {AbortSignal} from 'abort-controller';
|
||||
import Blob from 'fetch-blob';
|
||||
import * as Blob from 'fetch-blob';
|
||||
|
||||
type HeadersInit = Headers | string[][] | Record<string, string>;
|
||||
type AbortSignal = {
|
||||
readonly aborted: boolean;
|
||||
|
||||
addEventListener(type: "abort", listener: (this: AbortSignal, ev: Event) => any, options?: boolean | { passive?: boolean; once?: boolean; }): void;
|
||||
removeEventListener(type: "abort", listener: (this: AbortSignal, ev: Event) => any, options?: boolean | { capture?: boolean; }): void;
|
||||
};
|
||||
|
||||
type HeadersInit = Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<Iterable<string>>;
|
||||
|
||||
/**
|
||||
* This Fetch API interface allows you to perform various actions on HTTP request and response headers.
|
||||
|
@ -15,38 +21,36 @@ type HeadersInit = Headers | string[][] | Record<string, string>;
|
|||
* You can add to this using methods like append() (see Examples.)
|
||||
* In all methods of this interface, header names are matched by case-insensitive byte sequence.
|
||||
* */
|
||||
interface Headers {
|
||||
append: (name: string, value: string) => void;
|
||||
delete: (name: string) => void;
|
||||
get: (name: string) => string | null;
|
||||
has: (name: string) => boolean;
|
||||
set: (name: string, value: string) => void;
|
||||
forEach: (
|
||||
declare class Headers {
|
||||
constructor(init?: HeadersInit);
|
||||
|
||||
append(name: string, value: string): void;
|
||||
delete(name: string): void;
|
||||
get(name: string): string | null;
|
||||
has(name: string): boolean;
|
||||
set(name: string, value: string): void;
|
||||
forEach(
|
||||
callbackfn: (value: string, key: string, parent: Headers) => void,
|
||||
thisArg?: any
|
||||
) => void;
|
||||
): void;
|
||||
|
||||
[Symbol.iterator]: () => IterableIterator<[string, string]>;
|
||||
[Symbol.iterator](): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all key/value pairs contained in this object.
|
||||
*/
|
||||
entries: () => IterableIterator<[string, string]>;
|
||||
entries(): IterableIterator<[string, string]>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all keys of the key/value pairs contained in this object.
|
||||
*/
|
||||
keys: () => IterableIterator<string>;
|
||||
keys(): IterableIterator<string>;
|
||||
/**
|
||||
* Returns an iterator allowing to go through all values of the key/value pairs contained in this object.
|
||||
*/
|
||||
values: () => IterableIterator<string>;
|
||||
values(): IterableIterator<string>;
|
||||
|
||||
/** Node-fetch extension */
|
||||
raw: () => Record<string, string[]>;
|
||||
raw(): Record<string, string[]>;
|
||||
}
|
||||
declare var Headers: {
|
||||
prototype: Headers;
|
||||
new (init?: HeadersInit): Headers;
|
||||
};
|
||||
|
||||
interface RequestInit {
|
||||
/**
|
||||
|
@ -94,23 +98,26 @@ type BodyInit =
|
|||
| URLSearchParams
|
||||
| NodeJS.ReadableStream
|
||||
| string;
|
||||
interface Body {
|
||||
type BodyType = { [K in keyof Body]: Body[K] };
|
||||
declare class Body {
|
||||
constructor(body?: BodyInit, opts?: { size?: number });
|
||||
|
||||
readonly body: NodeJS.ReadableStream | null;
|
||||
readonly bodyUsed: boolean;
|
||||
readonly size: number;
|
||||
buffer: () => Promise<Buffer>;
|
||||
arrayBuffer: () => Promise<ArrayBuffer>;
|
||||
blob: () => Promise<Blob>;
|
||||
json: () => Promise<unknown>;
|
||||
text: () => Promise<string>;
|
||||
|
||||
buffer(): Promise<Buffer>;
|
||||
arrayBuffer(): Promise<ArrayBuffer>;
|
||||
blob(): Promise<Blob>;
|
||||
json(): Promise<unknown>;
|
||||
text(): Promise<string>;
|
||||
}
|
||||
declare var Body: {
|
||||
prototype: Body;
|
||||
new (body?: BodyInit, opts?: {size?: number}): Body;
|
||||
};
|
||||
|
||||
type RequestRedirect = 'error' | 'follow' | 'manual';
|
||||
interface Request extends Body {
|
||||
type RequestInfo = string | Body;
|
||||
declare class Request extends Body {
|
||||
constructor(input: RequestInfo, init?: RequestInit);
|
||||
|
||||
/**
|
||||
* Returns a Headers object consisting of the headers associated with request. Note that headers added in the network layer by the user agent will not be accounted for in this object, e.g., the "Host" header.
|
||||
*/
|
||||
|
@ -131,52 +138,64 @@ interface Request extends Body {
|
|||
* Returns the URL of request as a string.
|
||||
*/
|
||||
readonly url: string;
|
||||
clone: () => Request;
|
||||
clone(): Request;
|
||||
}
|
||||
type RequestInfo = string | Body;
|
||||
declare var Request: {
|
||||
prototype: Request;
|
||||
new (input: RequestInfo, init?: RequestInit): Request;
|
||||
};
|
||||
|
||||
interface Response extends Body {
|
||||
declare class Response extends Body {
|
||||
constructor(body?: BodyInit | null, init?: ResponseInit);
|
||||
|
||||
readonly headers: Headers;
|
||||
readonly ok: boolean;
|
||||
readonly redirected: boolean;
|
||||
readonly status: number;
|
||||
readonly statusText: string;
|
||||
readonly url: string;
|
||||
clone: () => Response;
|
||||
clone(): Response;
|
||||
}
|
||||
|
||||
declare var Response: {
|
||||
prototype: Response;
|
||||
new (body?: BodyInit | null, init?: ResponseInit): Response;
|
||||
};
|
||||
declare class FetchError extends Error {
|
||||
constructor(message: string, type: string, systemError?: object);
|
||||
|
||||
declare function fetch(url: RequestInfo, init?: RequestInit): Promise<Response>;
|
||||
|
||||
declare namespace fetch {
|
||||
function isRedirect(code: number): boolean;
|
||||
}
|
||||
|
||||
interface FetchError extends Error {
|
||||
name: 'FetchError';
|
||||
[Symbol.toStringTag]: 'FetchError';
|
||||
type: string;
|
||||
code?: string;
|
||||
errno?: string;
|
||||
}
|
||||
declare var FetchError: {
|
||||
prototype: FetchError;
|
||||
new (message: string, type: string, systemError?: object): FetchError;
|
||||
};
|
||||
|
||||
export class AbortError extends Error {
|
||||
declare class AbortError extends Error {
|
||||
type: string;
|
||||
name: 'AbortError';
|
||||
[Symbol.toStringTag]: 'AbortError';
|
||||
}
|
||||
|
||||
export {Headers, Request, Response, FetchError};
|
||||
export default fetch;
|
||||
|
||||
declare function fetch(url: RequestInfo, init?: RequestInit): Promise<Response>;
|
||||
declare class fetch {
|
||||
static default: typeof fetch;
|
||||
}
|
||||
declare namespace fetch {
|
||||
export function isRedirect(code: number): boolean;
|
||||
|
||||
export {
|
||||
HeadersInit,
|
||||
Headers,
|
||||
|
||||
RequestInit,
|
||||
RequestRedirect,
|
||||
RequestInfo,
|
||||
Request,
|
||||
|
||||
BodyInit,
|
||||
|
||||
ResponseInit,
|
||||
Response,
|
||||
|
||||
FetchError,
|
||||
AbortError
|
||||
};
|
||||
|
||||
export interface Body extends BodyType { }
|
||||
}
|
||||
|
||||
export = fetch;
|
||||
|
|
|
@ -1,5 +1,9 @@
|
|||
import {expectType} from 'tsd';
|
||||
import fetch, {Request, Response, Headers, FetchError, AbortError} from '.';
|
||||
import {expectType, expectAssignable} from 'tsd';
|
||||
import AbortController from 'abort-controller';
|
||||
|
||||
import fetch, {Request, Response, Headers, Body, FetchError, AbortError} from '.';
|
||||
import * as _fetch from '.';
|
||||
import __fetch = require('.');
|
||||
|
||||
async function run() {
|
||||
const getRes = await fetch('https://bigfile.com/test.zip');
|
||||
|
@ -56,8 +60,42 @@ async function run() {
|
|||
}
|
||||
}
|
||||
|
||||
// export *
|
||||
const wildRes = await _fetch('https://google.com');
|
||||
expectType<boolean>(wildRes.ok);
|
||||
expectType<number>(wildRes.size);
|
||||
expectType<number>(wildRes.status);
|
||||
expectType<string>(wildRes.statusText);
|
||||
expectType<() => Response>(wildRes.clone);
|
||||
|
||||
// export = require
|
||||
const reqRes = await __fetch('https://google.com');
|
||||
expectType<boolean>(reqRes.ok);
|
||||
expectType<number>(reqRes.size);
|
||||
expectType<number>(reqRes.status);
|
||||
expectType<string>(reqRes.statusText);
|
||||
expectType<() => Response>(reqRes.clone);
|
||||
|
||||
// Others
|
||||
const response = new Response();
|
||||
expectType<string>(response.url);
|
||||
expectAssignable<Body>(response);
|
||||
|
||||
const abortController = new AbortController()
|
||||
const request = new Request('url', { signal: abortController.signal });
|
||||
expectAssignable<Body>(request);
|
||||
|
||||
new Headers({'Header': 'value'});
|
||||
// new Headers(['header', 'value']); // should not work
|
||||
new Headers([['header', 'value']]);
|
||||
new Headers(new Headers());
|
||||
new Headers([
|
||||
new Set(['a', '1']),
|
||||
['b', '2'],
|
||||
new Map([['a', null], ['3', null]]).keys()
|
||||
]);
|
||||
|
||||
fetch.isRedirect = (code: number) => true;
|
||||
}
|
||||
|
||||
run().finally(() => {
|
||||
|
|
|
@ -78,7 +78,8 @@
|
|||
"lib": [
|
||||
"es2018"
|
||||
],
|
||||
"allowSyntheticDefaultImports": true
|
||||
"allowSyntheticDefaultImports": false,
|
||||
"esModuleInterop": false
|
||||
}
|
||||
},
|
||||
"xo": {
|
||||
|
|
|
@ -24,7 +24,7 @@ function validateValue(value) {
|
|||
}
|
||||
|
||||
/**
|
||||
* @typedef {Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<string>[]} HeadersInit
|
||||
* @typedef {Headers | Record<string, string> | Iterable<readonly [string, string]> | Iterable<Iterable<string>>} HeadersInit
|
||||
*/
|
||||
|
||||
/**
|
||||
|
|
Loading…
Reference in New Issue