verifica errore typeof in JS


153

In JS non sembra possibile verificare se un argomento passato a una funzione è in realtà del tipo "errore" o un'istanza di errore.

Ad esempio, questo non è valido:

typeof err === 'error'

poiché ci sono solo 6 tipi possibili (sotto forma di stringhe):

L'operatore typeof restituisce le informazioni sul tipo come stringa. Esistono sei valori possibili che typeofrestituiscono:

"number", "string", "boolean", "object", "function" e "undefined".

MSDN

E se avessi un semplice caso d'uso come questo:

function errorHandler(err) {

    if (typeof err === 'error') {
        throw err;
    }
    else {
        console.error('Unexpectedly, no error was passed to error handler. But here is the message:',err);
    }
}

quindi qual è il modo migliore per determinare se un argomento è un'istanza di errore?

è l' instanceofoperatore di qualche aiuto?


10
Sì, usaerr instanceof Error
— colecmc

2
@colecmc non sarà problematico se l'errore potrebbe provenire dal codice in un frame o in un'altra finestra? In tal caso ci saranno diversi prototipi di oggetti Error e instanceof non funzionerà come previsto. (vedi developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/… )
— Doin,

@Doin, io non la penso così. Convaliderà semplicemente l'oggetto di errore effettivo.
— colecmc,

1
@colecmc, penso che scoprirai che se hai lanciato err(diciamo) un iframe, ma poi lo passi alla finestra padre per la consegna, otterrai (err instanceof Error) === false. Questo perché iframe e la sua finestra principale hanno Errorprototipi di oggetti distinti e diversi . Allo stesso modo un oggetto come obj = {};volontà, quando viene passato a una funzione in esecuzione in una finestra diversa, genera (obj instanceof Object)===false. (Ancora peggio, in IE, se si mantiene un riferimento a obj dopo che la sua finestra è stata distrutta o navigata, tentando di chiamare il prototipo di oggetto fn come se obj.hasOwnProperty()si generassero errori!)
— Doin

come si controlla il tipo di errore? cioè catch((err)=>{if (err === ENOENT)restituisce ENOENT is not definederrore?
— Oldboy,

Risposte:


261

Puoi usare l' instanceofoperatore (ma vedi le avvertenze qui sotto!).

var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

Quanto sopra non funzionerà se l'errore è stato generato in una finestra / frame / iframe diversa da quella in cui si verifica il controllo. In tal caso, il instanceof Errorcontrollo restituirà false, anche per un Erroroggetto. In tal caso, l'approccio più semplice è la tipizzazione anatra.

if (myError && myError.stack && myError.message) {
  // it's an error, probably
}

Tuttavia, la tipizzazione anatra può produrre falsi positivi se si dispone di oggetti che non contengono errori stacke messageproprietà.


1
@ AurélienRibon Funziona bene con ReferenceErrorun'istanza. Stai controllando l' ReferenceErroroggetto globale . Prova questo: try { foo } catch (e) { console.log(e instanceof Error) }registra true. Se si sta cercando di controllare la globale ReferenceErroroggetto per qualche motivo, è possibile utilizzareError.isPrototypeOf(ReferenceError)
— Trott

1
@ AurélienRibon (Uh, anche, sì, non ero sicuro se stavi dicendo "Questo non funzionerà con un ReferenceError" che non è corretto, o se stavi solo sottolineando "Questo non funzionerà con l'oggetto globale ReferenceError" il che è assolutamente corretto, anche se faccio fatica a trovare una situazione in cui si verificherebbe ciò, ma ciò potrebbe dire di più sulla mia mancanza di immaginazione che sulla validità del caso d'uso).
— Trott,

Haha, scusa per quei ragazzi, sono stato bloccato in uno strano errore in cui tutte le mie ReferenceErroristanze non erano casi Error. Ciò è dovuto a una chiamata al vm.runInNewContext()nodo in, in cui sono stati ridefiniti tutti i prototipi standard. Tutti i miei risultati non erano istanze di oggetti standard. Stavo guardando in SO su questo e sono caduto in questo thread :)
— Aurelien Ribon,

1
Puoi provareconst error = (err instanceof Error || err instanceof TypeError) ? err : new Error(err.message ? err.message : err);
— Aamir Afridi,

come si controlla se si tratta di un instanceoftipo specifico di errore?
— oldboy

25

Ho posto la domanda originale: la risposta di @ Trott è sicuramente la migliore.

Tuttavia, con JS un linguaggio dinamico e con così tanti ambienti di runtime JS, l' instanceofoperatore può fallire soprattutto nello sviluppo front-end quando attraversa confini come iframe. Vedi: https://github.com/mrdoob/three.js/issues/5886

Se stai bene con la digitazione dell'anatra, questo dovrebbe essere buono:

let isError = function(e){
 return e && e.stack && e.message;
}

Personalmente preferisco le lingue tipizzate staticamente, ma se stai usando una lingua dinamica, è meglio abbracciare una lingua dinamica per quello che è, piuttosto che forzarla a comportarsi come una lingua tipizzata staticamente.

se volessi essere un po 'più preciso, potresti farlo:

   let isError = function(e){
     return e && e.stack && e.message && typeof e.stack === 'string' 
            && typeof e.message === 'string';
    }

3
Preferisco questa versione quando scrivo una funzione di utilità o una libreria. Non vincola gli utenti a un particolare contesto globale e gestisce anche correttamente gli errori deserializzati di JSON.
— ridacchia il

grazie, sì, in molti casi, se sembra un errore, possiamo trattarlo come un errore. in alcuni casi la tipizzazione di anatre è totalmente accettabile, in alcuni casi non è affatto accettabile, in questo caso, perfettamente bene.
— Alexander Mills,

Ho fatto un po 'di debug usando un debugger e stack e message sembrano davvero essere le uniche due proprietà non native nelle istanze Error.
— Alexander Mills,

1
@Trott potresti essere interessato a conoscere l' instanceofoperatore che non riesce in alcuni casi, vedi l'articolo collegato.
— Alexander Mills,

1
Questo è in realtà il più semplice, quindi funziona con i diversi tipi di errori (ad es Error. ReferenceError, ...). E nel mio ambiente, il instanceoffallimento fallisce miseramente in molte circostanze.
— Alexis Wilke,

10
var myError = new Error('foo');
myError instanceof Error // true
var myString = "Whatever";
myString instanceof Error // false

L'unico problema è questo

myError instanceof Object // true

Un'alternativa a questa sarebbe usare la proprietà del costruttore.

myError.constructor === Object // false
myError.constructor === String // false
myError.constructor === Boolean // false
myError.constructor === Symbol // false
myError.constructor === Function // false
myError.constructor === Error // true

Sebbene si noti che questa corrispondenza è molto specifica, ad esempio:

myError.constructor === TypeError // false

2

Puoi usare Object.prototype.toStringper verificare facilmente se un oggetto è un Error, che funzionerà anche per diversi frame.

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}

function isError(obj){
    return Object.prototype.toString.call(obj) === "[object Error]";
}
console.log("Error:", isError(new Error));
console.log("RangeError:", isError(new RangeError));
console.log("SyntaxError:", isError(new SyntaxError));
console.log("Object:", isError({}));
console.log("Array:", isError([]));


1

Puoi utilizzare obj.constructor.name per controllare la "classe" di un oggetto https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Function/name#Function_names_in_classes

Per esempio

var error = new Error("ValidationError");
console.log(error.constructor.name);

La riga sopra registrerà "Errore" che è il nome della classe dell'oggetto. Questo potrebbe essere usato con qualsiasi classe in javascript, se la classe non sta usando una proprietà che va sotto il nome "nome"


Questo non è affidabile quando si minimizza il codice e si usano sottoclassi di errori
— felixfbecker

1

Grazie @Trott per il tuo codice, ho appena usato lo stesso codice e ho aggiunto un esempio di lavoro in tempo reale a beneficio di altri.

<html>
<body >

<p>The **instanceof** operator returns true if the specified object is an instance of the specified object.</p>



<script>
	var myError = new Error("TypeError: Cannot set property 'innerHTML' of null"); // error type when element is not defined
	myError instanceof Error // true
	
	
	
	
	function test(){
	
	var v1 = document.getElementById("myid").innerHTML ="zunu"; // to change with this
	
	try {
		  var v1 = document.getElementById("myidd").innerHTML ="zunu"; // exception caught
		  } 
		  
	catch (e) {
		  if (e instanceof Error) {
			console.error(e.name + ': ' + e.message) // error will be displayed at browser console
		  }
  }
  finally{
		var v1 = document.getElementById("myid").innerHTML ="Text Changed to Zunu"; // finally innerHTML changed to this.
	}
	
	}
	
</script>
<p id="myid">This text will change</p>
<input type="button" onclick="test();">
</body>
</html>


0

Oppure usa questo per diversi tipi di errori

function isError(val) {
  return (!!val && typeof val === 'object')
    && ((Object.prototype.toString.call(val) === '[object Error]')
      || (typeof val.message === 'string' && typeof val.name === 'string'))
}
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.