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:
Maxime LUCE 2020-05-29 02:41:26 +02:00 committed by GitHub
parent 769f75d054
commit e6bfe4d419
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 119 additions and 61 deletions

133
@types/index.d.ts vendored
View File

@ -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;

View File

@ -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(() => {

View File

@ -78,7 +78,8 @@
"lib": [
"es2018"
],
"allowSyntheticDefaultImports": true
"allowSyntheticDefaultImports": false,
"esModuleInterop": false
}
},
"xo": {

View File

@ -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
*/
/**