Skip to content

Commit

Permalink
feat: Extend instanceof Support for GaxiosError (#593)
Browse files Browse the repository at this point in the history
  • Loading branch information
danielbankhead committed Dec 7, 2023
1 parent 48853bb commit 4fd1fe2
Show file tree
Hide file tree
Showing 3 changed files with 71 additions and 1 deletion.
41 changes: 40 additions & 1 deletion src/common.ts
Expand Up @@ -14,8 +14,16 @@
import {Agent} from 'http';
import {URL} from 'url';

/* eslint-disable @typescript-eslint/no-explicit-any */
import {pkg} from './util';

/**
* Support `instanceof` operator for `GaxiosError`s in different versions of this library.
*
* @see {@link GaxiosError[Symbol.hasInstance]}
*/
export const GAXIOS_ERROR_SYMBOL = Symbol.for(`${pkg.name}-gaxios-error`);

/* eslint-disable-next-line @typescript-eslint/no-explicit-any */
export class GaxiosError<T = any> extends Error {
/**
* An Error code.
Expand All @@ -34,6 +42,37 @@ export class GaxiosError<T = any> extends Error {
*/
status?: number;

/**
* Support `instanceof` operator for `GaxiosError` across builds/duplicated files.
*
* @see {@link GAXIOS_ERROR_SYMBOL}
* @see {@link GaxiosError[Symbol.hasInstance]}
* @see {@link https://github.com/microsoft/TypeScript/issues/13965#issuecomment-278570200}
* @see {@link https://stackoverflow.com/questions/46618852/require-and-instanceof}
* @see {@link https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/@@hasInstance#reverting_to_default_instanceof_behavior}
*/
[GAXIOS_ERROR_SYMBOL] = pkg.version;

/**
* Support `instanceof` operator for `GaxiosError` across builds/duplicated files.
*
* @see {@link GAXIOS_ERROR_SYMBOL}
* @see {@link GaxiosError[GAXIOS_ERROR_SYMBOL]}
*/
static [Symbol.hasInstance](instance: unknown) {
if (
instance &&
typeof instance === 'object' &&
GAXIOS_ERROR_SYMBOL in instance &&
instance[GAXIOS_ERROR_SYMBOL] === pkg.version
) {
return true;
}

// fallback to native
return Function.prototype[Symbol.hasInstance].call(GaxiosError, instance);
}

constructor(
message: string,
public config: GaxiosOptions,
Expand Down
17 changes: 17 additions & 0 deletions src/util.ts
@@ -0,0 +1,17 @@
// Copyright 2023 Google LLC
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

export const pkg: {
name: string;
version: string;
} = require('../../package.json');
14 changes: 14 additions & 0 deletions test/test.getch.ts
Expand Up @@ -26,6 +26,8 @@ import {
GaxiosResponse,
GaxiosPromise,
} from '../src';
import {GAXIOS_ERROR_SYMBOL} from '../src/common';
import {pkg} from '../src/util';
import qs from 'querystring';
import fs from 'fs';
import {Blob} from 'node-fetch';
Expand Down Expand Up @@ -119,6 +121,18 @@ describe('🚙 error handling', () => {
assert(error.response, undefined);
assert.equal(error.response.data, notJSON);
});

it('should support `instanceof` for GaxiosErrors of the same version', () => {
class A extends GaxiosError {}

const wrongVersion = {[GAXIOS_ERROR_SYMBOL]: '0.0.0'};
const correctVersion = {[GAXIOS_ERROR_SYMBOL]: pkg.version};
const child = new A('', {});

assert.equal(wrongVersion instanceof GaxiosError, false);
assert.equal(correctVersion instanceof GaxiosError, true);
assert.equal(child instanceof GaxiosError, true);
});
});

describe('🥁 configuration options', () => {
Expand Down

0 comments on commit 4fd1fe2

Please sign in to comment.