ईएस 6 सिंटैक्स और बैबेल के साथ जावास्क्रिप्ट में त्रुटि का विस्तार


132

मैं ES6 और बैबेल के साथ एरर बढ़ाने की कोशिश कर रहा हूं। यह काम नहीं कर रहा है।

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

त्रुटि ऑब्जेक्ट को कभी सही संदेश सेट नहीं मिलता है।

बैबल REPL में प्रयास करें

अब मैंने SO ( उदाहरण के लिए ) पर कुछ समाधान देखे हैं , लेकिन वे सभी बहुत un-ES6-y लगते हैं। यह एक अच्छा, ES6 तरीके से कैसे करें? (यह बाबेल में काम कर रहा है)


2
Babel REPL के आपके लिंक का अनुसरण करने से लगता है कि यह अब सही ढंग से काम करता है। मुझे लगता है कि यह बेबल में एक बग था जो तब से तय किया गया है।
kybernetikos

जवाबों:


188

करेल बिलेक के जवाब के आधार पर, मैं इसमें थोड़ा बदलाव करूंगा 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);

यह MyErrorस्टैक में प्रिंट करेगा , और जेनेरिक नहीं Error

यह स्टैक ट्रेस में त्रुटि संदेश भी जोड़ देगा - जो कि कारेल के उदाहरण से गायब था।

यह captureStackTraceउपलब्ध होने पर भी उपयोग करेगा ।

बाबेल 6 के साथ, आपको काम करने के लिए ट्रांसफॉर्म-बिल्टिन- एक्सटेंड ( एनपीएम ) की आवश्यकता है।


1
@ मिचैलयूनकिन if (typeof Error.captureStackTrace === 'function') { Error.captureStackTrace(this, this.constructor.name) } else { this.stack = (new Error(message)).stack; } । मेरा तर्क है कि यदि यह उपलब्ध है तो इस फ़ंक्शन का उपयोग करना बेहतर है, क्योंकि यह अधिक 'देशी' कॉल स्टैक प्रदान करता है और त्रुटि ऑब्जेक्ट का नाम प्रिंट करता है। बेशक, अगर आप सर्वर-साइड (नोड) पर भी इसका पूरा उपयोग कर रहे हैं, तो यह भी कोई समस्या नहीं है।
ली बेन्सन

4
@MichaelYounkin मुझे नहीं लगता कि यह एक गिरावट का हकदार है। ओपी ने ES6 में त्रुटियों का विस्तार करने की बात की। उस तर्क के बाद, लगभग सभी ES6 कम से कम एक ब्राउज़र से गायब हैं। मेरा समाधान (अतिरिक्त फ़ेक चेक के साथ) सबसे व्यापक रूप से उपयोग किए जाने वाले ब्राउज़र में देशी कवरेज प्रदान करता है, हर दूसरे में फ़ॉल-बैक और Node.js. में 100% कवरेज। मैं मानता हूँ कि यदि आप किस क्लास क्लास में लगातार त्रुटि करते हैं तो this.stack = (new Error(message)).stackआपको वह मिल जाता है ... लेकिन व्यवहार में, यह शायद बहुत बड़ी बात नहीं है।
ली बेन्सन

6
यह new MyError('foo') instanceof MyError === false
बबेल

5
इस कोड को एनपीएम मॉड्यूल के रूप में extendable-error-class बाबेल के साथ संकलित किया गया: npmjs.com/package/extendable-error-class जो बाबेल -प्लगइन-ट्रांसफॉर्मेशन-
बिल्ड

3
this.message = message;के साथ बेमानी हैsuper(message);
मैथ्यूग

39

इस उत्तर , इस उत्तर और इस कोड को मिलाकर , मैंने इस छोटे "सहायक" वर्ग को बनाया है, जो ठीक काम करता है।

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 में प्रयास करें


1
this.stack = (new Error(message)).stack;- अन्यथा स्टैकट्रेस से संदेश गायब है
ली बेन्सन

3
मुझे संदेह है कि यह आवश्यकतानुसार काम नहीं करता है, क्योंकि यदि आप ऐसा करते हैं: कंसोल.लॉग (माइरोर इंस्टोफ़ एक्सटेंडेबेलर); यह अभी भी झूठा कहता है ..
मौनो वैह

4
एक ही समस्या है, Instof का उपयोग करके CustomError काम नहीं करता है, अगर आप Instof का उपयोग नहीं कर सकते हैं तो क्या बात है।
gre

messageत्रुटि स्टैक कंस्ट्रक्टर में जोड़कर इसे बेहतर बनाया जा सकता है , इसलिए इसे फेंकने पर स्टैक के शीर्ष पर सही संदेश दिखाई देता है:this.stack = (new Error(message)).stack;
सेबस्टियन

1
myerror.nameअब "त्रुटि" देता है। यकीन नहीं होता है कि यह babel.See @ sukima के उत्तरार्ध के बाद के संस्करणों से संबंधित है
एरिक एच।

27

अंत में इसे आराम करने के लिए रखें। कोलाहल 6 में यह स्पष्ट है कि डेवलपर्स है का समर्थन नहीं करते में बनाया से फैला हुआ है। हालांकि इस चाल नहीं होगा बातें करने में मदद करना Map, Setआदि इसके लिए काम करता है Error। यह एक भाषा के मूल विचारों में से एक के रूप में महत्वपूर्ण है जो अपवाद को फेंक सकता है, कस्टम त्रुटियों की अनुमति देता है। यह दोगुना महत्वपूर्ण है क्योंकि वादे एक त्रुटि को अस्वीकार करने के लिए डिज़ाइन किए जाने के बाद से अधिक उपयोगी हो जाते हैं ।

दुखद सच्चाई यह है कि आपको अभी भी ES2015 में पुराने तरीके से प्रदर्शन करने की आवश्यकता है।

बाबेल REPL में उदाहरण

कस्टम त्रुटि पैटर्न

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

दूसरी ओर यह अनुमति देने के लिए बैबल 6 के लिए एक प्लगइन है।

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

अपडेट: (2016-09-29 तक) कुछ परीक्षण के बाद ऐसा प्रतीत होता है कि babel.io सभी एसेर्ट्स (कस्टम विस्तारित त्रुटि से विस्तार) के लिए ठीक से खाता नहीं है। लेकिन Ember.JS में त्रुटि के विस्तार की उम्मीद के अनुसार काम करता है: https://ember-twiddle.com/d88555a6f408174df0a4c8e0fd6b27ce


हां, लिंक किए गए बेबल प्लगइन के साथ यह स्वीकृत उत्तर के साथ सही ढंग से काम करता है। (हालांकि, परिणामी फ़ाइल नोड में काम नहीं करती है, क्योंकि इसमें रिफ्लेक्ट नहीं होता है, जाहिरा तौर पर)
कारेल बिलेक

एक जिज्ञासा के रूप में, अगर ES2016 चश्मा कहता है कि बिल्डरों को विस्तार योग्य है, तो v8 और बाबेल के es5 ट्रांसप्लीनिंग जैसे vms क्यों इसके खिलाफ हैं? क्या यह एक उचित उम्मीद नहीं है कि एक वर्ग उसी तरह एक वर्ग का विस्तार कर सकता है जैसे एक प्रोटोटाइप श्रृंखला अन्य प्रोटोटाइप से आ सकती है? एक प्लगइन में छिपी इस तरह की समारोह की आवश्यकता क्यों है?
सुकीमा

यह स्पष्ट रूप से निराशाजनक है जब अधिकांश मामलों में केवल साधारण वस्तुओं को बनाना चाहते हैं जो व्यवहार को साझा करते हैं। एक कस्टम त्रुटि जो उपयोग कर सकती है Error.toString()। इसे पूरा करने के लिए विशेष हूप्स और जाइरेशन करने की आवश्यकता है, अधिकांश देवता इससे बचेंगे और बुरे व्यवहार का सहारा लेंगे जैसे एरर्स के बजाय स्ट्रिंग्स को फेंकना। या वस्तुओं की तरह अपना खुद का नक्शा बना रहे हैं। ऐसे ओओपी तरीकों को रोकने की आवश्यकता क्यों है?
सुकिमा

मेरी राय में वे इसके खिलाफ नहीं हैं, यह सिर्फ कुछ तकनीकी समस्या है। हालांकि मुझे यकीन नहीं है! आप उनसे पूछ सकते हैं :) परियोजनाएं काफी खुली हैं
कारेल बिलेक

इस विषय पर अब तक के सभी सवालों के जवाब बाबुल पर "बाबेल का समर्थन नहीं करता" है, मुझे लगा कि यह बातचीत का अंत था। मेरे गोमांस समर्थन की कमी एक आम OOP मुहावरे को मुश्किल बना देती है और मुझे बॉयलर-क्रॉफ्ट पर उन्हें प्राप्त करने के लिए सह-वोकर से भी लड़ना पड़ता है। मैं बस यहाँ एक वैकल्पिक वैकल्पिक वैकल्पिक हल चाहता था। एक प्लगइन जोड़ने लगता है तो सबसे अच्छा विकल्प है।
13:27 पर सुकीमा

15

संपादित करें : टाइपस्क्रिप्ट 2.1 में परिवर्तन तोड़ना

त्रुटि, सरणी और मानचित्र जैसे अंतर्निहित इंसर्ट अब काम नहीं कर सकते हैं।

एक सिफारिश के रूप में, आप किसी भी सुपर (...) कॉल के तुरंत बाद मैन्युअल रूप से प्रोटोटाइप को समायोजित कर सकते हैं।

एडिंग ली बेन्सन मूल उत्तर मेरे लिए थोड़ा काम करता है। यह उदाहरण के लिए वर्ग के stackअतिरिक्त और अतिरिक्त तरीके भी जोड़ता है ExtendableError

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

1
आप कॉल करने की आवश्यकता Object.setPrototypeOfमें MyErrorभी निर्माता। stackoverflow.com/a/41102306/186334 github.com/Microsoft/TypeScript-wiki/blob/master/…
CallMeLaNN

10

बैबल 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');

6

का हवाला देते हुए

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 consoleऔर Node.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

4

@ ज़ंगव के उत्तर के अलावा, आप अपनी त्रुटियों को इस तरह परिभाषित कर सकते हैं:

'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

4
यह काम नहीं करता है new MyError('foo') instanceof MyError === false:।
सुकिमा

1
यह करता है, पर Node.js v7.7.3
गनर गेसनर

2

मैं ES6 के साथ एरर को बढ़ाने की कोशिश कर रहा हूं

वह class MyError extends Error {…}वाक्य रचना सही है।

ध्यान दें कि अभी भी ट्रांसपॉयलर को अंतर्निहित वस्तुओं से विरासत में मिली समस्याएं हैं। आपके मामले में,

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

समस्या को ठीक करने के लिए लगता है।


सच! लेकिन संदेश वैसे भी सेट नहीं है - मैं एक नया उदाहरण लिखूंगा।
करेल बिलेक

मैंने अब उदाहरण फिर से लिखा है
करेल बिलेक


"सुपर (एम)" एक खाली वस्तु लौटाएगा, जाहिरा तौर पर। तो Object.assign मदद नहीं करता है।
कारेल बिलेक

@ KarelBílek: आप किस ब्राउज़र का उपयोग कर रहे हैं? Error.call()मेरे लिए एक नया त्रुटि उदाहरण लौटाता है।
बेर्गी

2

यह देखते हुए स्वीकार किए जाते हैं जवाब अब काम नहीं करता तो आप हमेशा एक विकल्प (के रूप में एक कारखाने इस्तेमाल कर सकते हैं 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);


स्वीकृत उत्तर अभी भी मेरे लिए काम करता है, यदि आपके पास आवश्यक बैबिल प्लगइन्स हैं। इस उत्तर के लिए भी धन्यवाद, हालांकि!
करेल बिलेक

2

मैं ऊपर वर्णित से अधिक मजबूत वाक्यविन्यास पसंद करता हूं। त्रुटि प्रकार के अतिरिक्त तरीके आपको सुंदर 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;
    }
}

इस कोड का परीक्षण करने के लिए आप कुछ समान चला सकते हैं:

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

    console.warn(message);
}

का विस्तार CustomErrorप्रकार स्वागत है। यह विस्तारित प्रकार या ओवरराइड मौजूदा करने के लिए कुछ विशिष्ट कार्यक्षमता जोड़ने के लिए संभव है। उदाहरण के लिए।

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}.`;
    }
}

1

@sukima का उल्लेख किया है, आप देशी जे एस विस्तार नहीं कर सकते। ओपी के प्रश्न का उत्तर नहीं किया जा सकता।

मेलबोर्न 2991 के उत्तर के समान , मैंने एक कारखाने का उपयोग किया, लेकिन ग्राहक त्रुटि प्रकारों के लिए एमडीएन की सिफारिश का पालन ​​किया ।

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

1

यह मेरे लिए काम करता है:

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

0

बाबेल का उपयोग नहीं कर रहा है, लेकिन सादे ES6 में, निम्नलिखित मेरे लिए ठीक काम करता है:

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

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 ...'

आप देख सकते हैं, ढेर दोनों त्रुटि नाम और संदेश है। मुझे यकीन नहीं है कि अगर मुझे कुछ याद आ रहा है, लेकिन अन्य सभी उत्तर अति-जटिल चीजों के लिए प्रतीत होते हैं।


0

मैंने इस तरह @Lee बेन्सन के समाधान में थोड़ा सुधार किया:

extendableError.js

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


}

export default ExtendableError

एक त्रुटि का एक उदाहरण

import ExtendableError from './ExtendableError'

const AuthorizationErrors = {
    NOT_AUTHORIZED: 401,
    BAD_PROFILE_TYPE: 402,
    ROLE_NOT_ATTRIBUTED: 403
}

class AuthorizationError extends ExtendableError {
    static errors = AuthorizationErrors 
}

export default AuthorizationError 

उसके बाद आप समूह त्रुटियों करने में सक्षम हैं, जबकि विकल्प विनिर्देशक होने क्या आपके आवेदन विशिष्ट स्थितियों में से कुछ में अलग ढंग से करने का फैसला करने के लिए

new AuthorizationError ("The user must be a seller to be able to do a discount", AuthorizationError.errors.BAD_PROFILE_TYPE )
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.