IT박스

ES6 구문 및 Babel을 사용하여 Javascript에서 오류 확장

itboxs 2020. 7. 4. 11:17
반응형

ES6 구문 및 Babel을 사용하여 Javascript에서 오류 확장


ES6 및 Babel에서 오류를 확장하려고합니다. 작동하지 않습니다.

class MyError extends Error {
  constructor(m) {
    super(m);
  }
}

var error = new Error("ll");
var myerror = new MyError("ll");
console.log(error.message) //shows up correctly
console.log(myerror.message) //shows empty string

Error 객체는 올바른 메시지 세트를 얻지 못합니다.

Babel REPL에서 시도하십시오 .

이제 SO에 대한 몇 가지 솔루션 ( 예 : here )을 보았지만 모두 매우 ES6이 아닌 것처럼 보입니다. ES6 방식으로 좋은 방법은 무엇입니까? (바벨에서 일하고 있습니다)


Karel Bílek의 답변에 따라 constructor다음과 같이 약간 변경했습니다 .

class ExtendableError extends Error {
  constructor(message) {
    super(message);
    this.name = this.constructor.name;
    if (typeof Error.captureStackTrace === 'function') {
      Error.captureStackTrace(this, this.constructor);
    } else { 
      this.stack = (new Error(message)).stack; 
    }
  }
}    

// now I can extend

class MyError extends ExtendableError {}

var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);

이것은 MyErrorgeneric이 아닌 스택에 인쇄 됩니다 Error.

또한 Karel의 예제에서 누락 된 오류 추적을 스택 추적에 추가합니다.

사용 captureStackTrace가능한 경우 에도 사용 됩니다.

Babel 6을 사용하려면 변환 내장 확장 ( npm )이 필요합니다.


이 답변 , 이 답변이 코드를 결합 하여이 작은 "도우미"클래스를 만들었습니다.

class ExtendableError extends Error {
  constructor(message) {
    super();
    this.message = message; 
    this.stack = (new Error()).stack;
    this.name = this.constructor.name;
  }
}    

// now I can extend

class MyError extends ExtendableError {
  constructor(m) {   
    super(m);
  }
}

var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);

REPL 시도


마침내 이것을 쉬게했다. 바벨 6 개발자가 명시 적입니다 지원하지 않는 내장에서 연장.이 트릭은 있지만 하지 않을 것 도움이 좋아 Map, Set이에 대한 작업을 수행 등 Error. 예외를 던질 수있는 언어의 핵심 아이디어 중 하나는 맞춤 오류를 허용하는 것이므로 중요합니다. 약속을 더 유용하게 만들 때 오류 가 발생하도록 설계 되었기 때문에이 점이 두 배로 중요합니다 .

슬픈 사실은 여전히 ​​ES2015 에서이 방법을 수행해야한다는 것입니다.

Babel REPL의 예

맞춤 오류 패턴

class MyError {
  constructor(message) {
    this.name = 'MyError';
    this.message = message;
    this.stack = new Error().stack; // Optional
  }
}
MyError.prototype = Object.create(Error.prototype);

반면에 Babel 6 용 플러그인이 있습니다.

https://www.npmjs.com/package/babel-plugin-transform-builtin-extend

업데이트 : (2016-09-29 기준) 일부 테스트 후 babel.io가 모든 어설 션을 올바르게 설명하지 않는 것으로 보입니다 (사용자 정의 확장 오류에서 끝남). 그러나 Ember.JS에서 확장 오류가 예상대로 작동합니다 : https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce


편집 : Typescript 2.1의 주요 변경 사항

오류, 배열 및 맵과 같은 기본 제공 확장 기능이 더 이상 작동하지 않을 수 있습니다.

권장 사항으로, super (...) 호출 직후 프로토 타입을 수동으로 조정할 수 있습니다.

Lee Benson 원래 답변을 편집하면 약간 효과적입니다. 또한 인스턴스 stackExtendableError클래스의 메소드를 추가 하고 추가 합니다.

class ExtendableError extends Error {
   constructor(message) {
       super(message);
       Object.setPrototypeOf(this, ExtendableError.prototype);
       this.name = this.constructor.name;
   }

   dump() {
       return { message: this.message, stack: this.stack }
   }
 }    

class MyError extends ExtendableError {
    constructor(message) {
        super(message);
        Object.setPrototypeOf(this, MyError.prototype);
    }
}

var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror.dump());
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);

babel 6의 최신 변경 사항으로 인해 변형 내장 확장 프로그램이 더 이상 작동하지 않습니다. 이 혼합 접근법을 사용하여 끝났습니다.

export default class MyError {
    constructor (message) {
        this.name = this.constructor.name;
        this.message = message;
        this.stack = (new Error(message)).stack;
    }
}

MyError.prototype = Object.create(Error.prototype);
MyError.prototype.constructor = MyError;

import MyError from './MyError';

export default class MyChildError extends MyError {
    constructor (message) {
        super(message);
    }
}

결과적으로 이러한 모든 테스트는 통과합니다.

const sut = new MyError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut.name).toBe('MyError');
expect(typeof sut.stack).toBe('string');

const sut = new MyChildError('error message');
expect(sut.message).toBe('error message');
expect(sut).toBeInstanceOf(Error);
expect(sut).toBeInstanceOf(MyError);
expect(sut).toBeInstanceOf(MyChildError);
expect(sut.name).toBe('MyChildError');
expect(typeof sut.stack).toBe('string');

인용

class MyError extends Error {
  constructor(message) {
    super(message);
    this.message = message;
    this.name = 'MyError';
  }
}

전화 this.stack = (new Error()).stack;덕분 트릭이 필요하지 않습니다 super().

스택 추적하지 않는 한 위의 코드를 출력 할 수 없습니다 만 this.stack = (new Error()).stack;이상이 Error.captureStackTrace(this, this.constructor.name);에서 호출 바벨 . IMO, 여기에 하나의 문제가 있습니다.

사실, 스택 추적에서 출력을 할 수 있습니다 Chrome consoleNode.js v4.2.1이 코드 조각으로.

class MyError extends Error{
        constructor(msg) {
                super(msg);
                this.message = msg;
                this.name = 'MyError';
        }
};

var myerr = new MyError("test");
console.log(myerr.stack);
console.log(myerr);

의 출력 Chrome console.

MyError: test
    at MyError (<anonymous>:3:28)
    at <anonymous>:12:19
    at Object.InjectedScript._evaluateOn (<anonymous>:875:140)
    at Object.InjectedScript._evaluateAndWrap (<anonymous>:808:34)
    at Object.InjectedScript.evaluate (<anonymous>:664:21)

출력 Node.js

MyError: test
    at MyError (/home/bsadmin/test/test.js:5:8)
    at Object.<anonymous> (/home/bsadmin/test/test.js:11:13)
    at Module._compile (module.js:435:26)
    at Object.Module._extensions..js (module.js:442:10)
    at Module.load (module.js:356:32)
    at Function.Module._load (module.js:311:12)
    at Function.Module.runMain (module.js:467:10)
    at startup (node.js:134:18)
    at node.js:961:3

@zangw 답변 외에도 다음과 같이 오류를 정의 할 수 있습니다.

'use strict';

class UserError extends Error {
  constructor(msg) {
    super(msg);
    this.name = this.constructor.name;
  }
}

// define errors
class MyError extends UserError {}
class MyOtherError extends UserError {}

console.log(new MyError instanceof Error); // true

throw new MyError('My message');

올바른 이름, 메시지 및 스택 추적이 발생합니다.

MyError: My message
    at UserError (/Users/honzicek/Projects/api/temp.js:5:10)
    at MyError (/Users/honzicek/Projects/api/temp.js:10:1)
    at Object.<anonymous> (/Users/honzicek/Projects/api/temp.js:14:7)
    at Module._compile (module.js:434:26)
    at Object.Module._extensions..js (module.js:452:10)
    at Module.load (module.js:355:32)
    at Function.Module._load (module.js:310:12)
    at Function.Module.runMain (module.js:475:10)
    at startup (node.js:117:18)
    at node.js:951:3

ES6으로 오류를 확장하려고합니다.

class MyError extends Error {…}구문이 맞습니다.

트랜스 파일러에는 여전히 내장 객체에서 상속하는 데 문제가 있습니다. 귀하의 경우

var err = super(m);
Object.assign(this, err);

문제를 해결하는 것 같습니다.


이것이 받아 들여진 대답이 더 이상 효과가 없다면 항상 공장을 대안으로 사용할 수 있습니다 ( repl )

function ErrorFactory(name) {
   return class AppError extends Error {
    constructor(message) {
      super(message);
      this.name = name;
      this.message = message; 
      if (typeof Error.captureStackTrace === 'function') {
        Error.captureStackTrace(this, this.constructor);
      } else { 
        this.stack = (new Error(message)).stack; 
      }
    }
  }     
}

// now I can extend
const MyError = ErrorFactory("MyError");


var myerror = new MyError("ll");
console.log(myerror.message);
console.log(myerror instanceof Error);
console.log(myerror.name);
console.log(myerror.stack);


@sukima가 언급했듯이 네이티브 JS를 확장 할 수 없습니다. OP의 질문에 대답 할 수 없습니다.

Melbourne2991의 답변비슷하게 팩토리를 사용했지만 고객 오류 유형에 대한 MDN의 권장 사항을 따랐습니다 .

function extendError(className){
  function CustomError(message){
    this.name = className;
    this.message = message;
    this.stack = new Error().stack; // Optional
  }
  CustomError.prototype = Object.create(Error.prototype);
  CustomError.prototype.constructor = CustomError;
  return CustomError;
}

위에서 설명한 것보다 더 강력한 구문을 선호합니다. 오류 유형의 추가 방법은 예쁘 console.log거나 다른 것을 만드는 데 도움이됩니다 .

export class CustomError extends Error {
    /**
     * @param {string} message
     * @param {number} [code = 0]
     */
    constructor(message, code = 0) {
        super();

        /**
         * @type {string}
         * @readonly
         */
        this.message = message;

        /**
         * @type {number}
         * @readonly
         */
        this.code = code;

        /**
         * @type {string}
         * @readonly
         */
        this.name = this.constructor.name;

        /**
         * @type {string}
         * @readonly
         */
        this.stack = CustomError.createStack(this);
    }

    /**
     * @return {string}
     */
    toString() {
        return this.getPrettyMessage();
    }

    /**
     * @return {string}
     */
    getPrettyMessage() {
        return `${this.message} Code: ${this.code}.`;
    }

    /**
     * @param {CustomError} error
     * @return {string}
     * @private
     */
    static createStack(error) {
        return typeof Error.captureStackTrace === 'function'
            ? Error.captureStackTrace(error, error.constructor)
            : (new Error()).stack;
    }
}

To test this code you can run something similar:

try {
    throw new CustomError('Custom error was thrown!');
} catch (e) {
    const message = e.getPrettyMessage();

    console.warn(message);
}

Extending of CustomError type are welcome. It is possible to add some specific functionality to the extended type or override existing. For example.

export class RequestError extends CustomError {
    /**
     * @param {string} message
     * @param {string} requestUrl
     * @param {number} [code = 0]
     */
    constructor(message, requestUrl, code = 0) {
        super(message, code);

        /**
         * @type {string}
         * @readonly
         */
        this.requestUrl = requestUrl;
    }

    /**
     * @return {string}
     */
    getPrettyMessage() {
        const base = super.getPrettyMessage();

        return `${base} Request URL: ${this.requestUrl}.`;
    }
}

This works for me:

/**
 * @class AuthorizationError
 * @extends {Error}
 */
export class AuthorizationError extends Error {
    message = 'UNAUTHORIZED';
    name = 'AuthorizationError';
}

Not using Babel, but in plain ES6, the following seems to work fine for me:

class CustomError extends Error {
    constructor(...args) {
        super(...args);
        this.name = this.constructor.name;
    }
}

Testing from REPL:

> const ce = new CustomError('foobar');
> ce.name
'CustomError'
> ce.message
'foobar'
> ce instanceof CustomError
true
> ce.stack
'CustomError: foobar\n    at CustomError (repl:3:1)\n ...'

As you can see, the stack contains both the error name and message. I'm not sure if I'm missing something, but all the other answers seem to over-complicate things.

참고URL : https://stackoverflow.com/questions/31089801/extending-error-in-javascript-with-es6-syntax-babel

반응형