typescriptnode-fetch

TypeScript generic fetch function, wrong type for BodyInit


I don't understand this error. It says toBody() returns a Blob type. but to me it should return a string which is accepted by BodyInit

type BodyInit = Blob | BufferSource | FormData | URLSearchParams | ReadableStream<Uint8Array> | string;

export class CredentialsRequestBody
  implements RequestBody<CredentialsRequestBody> {
  constructor(username: string, password: string) {
    this.username = username;
    this.password = password;
  }
  username: string;
  password: string;
  toBody(): BodyInit {
    console.log(typeof JSON.stringify(Object.assign({}, this)).toString());
    return '{"username":"jonas", "password": "something"}'; //JSON.stringify(Object.assign({}, this)).toString();
  }
type methods = 'DELETE' | 'POST' | 'GET' | 'POST';
export async function request(
  url: string,
  method: methods,
  headers: any,
  body: RequestBody<any>
): Promise<any> {
  const defaultHeaders = {
    'Content-Type': 'application/json'
  };

  const requestOptions: RequestInit = {
    method: method !== null ? method : 'GET',
    headers:
      headers !== null
        ? {
            ...defaultHeaders,
            ...headers
          }
        : defaultHeaders
  };
  if (
    body !== null &&
    requestOptions.method !== 'GET' &&
    requestOptions.method !== 'DELETE'
  ) {
    requestOptions.body = body.toBody();
  }

  const response = await fetch(url, requestOptions);//<--requestOptions INVALID
  return response.json();
}
fetch/index").RequestInit'.
  Types of property 'body' are incompatible.
    Type 'BodyInit' is not assignable to type 'import("/home/jonas/WebstormProjects/mindtherags-backend/node_modules/@types/node-fetch/index").BodyInit'.
      Type 'Blob' is not assignable to type 'BodyInit'.
        Type 'Blob' is missing the following properties from type 'ArrayBuffer': byteLength, [Symbol.toStringTag]

29   const response = await fetch(url, requestOptions);
                                       ~~~~~~~~~~~~~~

[9:40:22 PM] Found 1 error. Watching for file changes.

even converting a string to a Blob and passing it directly as RequestInit.body yields the same error. Could the type be off?

  const requestOptions: RequestInit = {
    method: method !== null ? method : 'GET',
    headers:
      headers !== null
        ? {
            ...defaultHeaders,
            ...headers
          }
        : defaultHeaders,
    body: new Blob([JSON.stringify({ something: 'something' })], {
      type: 'text/plain'
    })
  };
  /*if (
    body !== null &&
    requestOptions.method !== 'GET' &&
    requestOptions.method !== 'DELETE'
  ) {
    requestOptions.body = JSON.stringify({ something: 'something' });
  }*/

  const response = await fetch(url, requestOptions);
  return response.json();
}
Argument of type 'RequestInit' is not assignable to parameter of type 'import("/home/jonas/WebstormProjects/mindtherags-backend/node_modules/@types/node-fetch/index").RequestInit'.
  Types of property 'body' are incompatible.
    Type 'BodyInit' is not assignable to type 'import("/home/jonas/WebstormProjects/mindtherags-backend/node_modules/@types/node-fetch/index").BodyInit'.
      Type 'Blob' is not assignable to type 'BodyInit'.
        Type 'Blob' is missing the following properties from type 'ArrayBuffer': byteLength, [Symbol.toStringTag]ts(2345)
    body: JSON.stringify({
      something: 'something'
    })

does not work either

uninstalling @types/node-fetch and fetching through anyways with Blob, JSON.stringify(obj) and toBody() as the body all yield the following error on the request

(node:145700) UnhandledPromiseRejectionWarning: TypeError: Cannot read property 'Symbol(Request internals)' of null

which is this function node-fetch

const INTERNALS$2 = Symbol('Request internals');

/**
* Check if a value is an instance of Request.
*
* @param   Mixed   input
* @return  Boolean
*/
function isRequest(input) {
   return typeof input === 'object' && typeof input[INTERNALS$2] === 'object';
}

Solution

  • I suspect that the typescript issue has to do with conflicting definitions is different places, since the error is specifically saying that your BodyInit type is not assignable to the one from the @types/node-fetch folder.

    RequestInit has a definition in lib.dom.d.ts which differs slightly from the one in the node-fetch package. For example dom allows BodyInit to be null but node-fecth doesn't.

    For the record, I'm not seeing any error in the Typescript Playground, but I think that's using the lib.dom definition for the fetch function.