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.