Ich versuche, einen benutzerdefinierten Fehler mit meinem in der Konsole gedruckten Klassennamen "CustomError" anstelle von "Fehler" auszulösen, ohne Erfolg:
class CustomError extends Error {
constructor(message: string) {
super(`Lorem "${message}" ipsum dolor.`);
this.name = 'CustomError';
}
}
throw new CustomError('foo');
Die Ausgabe ist Uncaught Error: Lorem "foo" ipsum dolor
.
Was ich erwarte : Uncaught CustomError: Lorem "foo" ipsum dolor
.
Ich frage mich, ob dies nur mit TS möglich ist (ohne mit JS-Prototypen herumzuspielen).
quelle
Object.setPrototypeOf(this, this.constructor.prototype)
wird nicht hier arbeiten, die Klasse explizit Bezug genommen werden muss.this.constructor
an dieser Stelle lesen könnten, wäre die Prototypenkette bereits intakt.Object.setPrototypeOf(this, new.target.prototype);
typescriptlang.org/docs/handbook/release-notes/...Das Problem ist, dass die in Javascript integrierte Klasse
Error
die Prototypenkette unterbricht, indem sie das zu erstellende Objekt (dhthis
) beim Aufrufen auf ein neues, anderes Objekt umschaltetsuper
und das neue Objekt nicht die erwartete Prototypenkette hat, dh es ist eine Instanz vonError
nicht vonCustomError
.Dieses Problem kann elegant mit 'new.target' gelöst werden, das seit Typescript 2.2 unterstützt wird. Siehe hier: https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html
class CustomError extends Error { constructor(message?: string) { // 'Error' breaks prototype chain here super(message); // restore prototype chain const actualProto = new.target.prototype; if (Object.setPrototypeOf) { Object.setPrototypeOf(this, actualProto); } else { this.__proto__ = actualProto; } } }
Die Verwendung
new.target
hat den Vorteil, dass Sie den Prototyp nicht wie bei einigen anderen hier vorgeschlagenen Antworten fest codieren müssen. Das hat wieder den Vorteil, dass Klassen von erbenCustomError
, automatisch auch die richtige Prototypkette erhalten.Wenn Sie den Prototyp (z. B.
Object.setPrototype(this, CustomError.prototype)
) fest codierenCustomError
würden , hätte er selbst eine funktionierende Prototypkette, aber alle Klassen, die von erben,CustomError
würden beschädigt, z. B.class VeryCustomError < CustomError
wären Instanzen von a nichtinstanceof VeryCustomError
wie erwartet, sondern nurinstanceof CustomError
.Siehe auch: https://github.com/Microsoft/TypeScript/issues/13965#issuecomment-278570200
quelle
this.__proto__
privat oder öffentlich sein?__proto__
Immobilie ist auch veraltet und nur etwas standardisiert, um etwas abwärtskompatibel zu sein. Weitere Informationen zu beiden finden Sie unter MDN .(this as any).__proto__ = actualProto;
. Das habe ich getan. Hacky, aber ich muss keine Klassendeklarationen ändern.Es funktioniert korrekt in ES2015 ( https://jsfiddle.net/x40n2gyr/ ). Das Problem besteht höchstwahrscheinlich darin, dass der TypeScript-Compiler auf ES5 transpiliert und
Error
nicht nur mit ES5-Funktionen korrekt in Unterklassen unterteilt werden kann. Es kann nur mit ES2015 und höheren Funktionen (class
oder, noch dunkler), korrekt in Unterklassen unterteilt werdenReflect.construct
. Dies liegt daran, dass beim AufrufenError
als Funktion (und nicht übernew
oder in ES2015super
oderReflect.construct
)this
eine neue Funktion ignoriert und erstellt wirdError
.Sie müssen wahrscheinlich mit der unvollständigen Ausgabe leben, bis Sie auf ES2015 oder höher zielen können ...
quelle
Ab TypeScript 2.2 kann dies über erfolgen
new.target.prototype
. https://www.typescriptlang.org/docs/handbook/release-notes/typescript-2-2.html#exampleclass CustomError extends Error { constructor(message?: string) { super(message); // 'Error' breaks prototype chain here this.name = 'CustomError'; Object.setPrototypeOf(this, new.target.prototype); // restore prototype chain } }
quelle
Ich bin vor ein paar Tagen in meinem Typoskript-Projekt auf dasselbe Problem gestoßen. Damit es funktioniert, verwende ich die Implementierung von MDN nur mit Vanilla Js. Ihr Fehler würde also ungefähr so aussehen:
function CustomError(message) { this.name = 'CustomError'; this.message = message || 'Default Message'; this.stack = (new Error()).stack; } CustomError.prototype = Object.create(Error.prototype); CustomError.prototype.constructor = CustomError; throw new CustomError('foo');
Es scheint im SO-Code-Snippet nicht zu funktionieren, aber in der Chrome-Konsole und in meinem Typoskript-Projekt:
quelle
strict: true
Gute Idee, aber es schlägt mit dieser Nachricht fehl, wenn in tsconfig: stackoverflow.com/questions/43623461/…Versuche dies...
class CustomError extends Error { constructor(message: string) { super(`Lorem "${message}" ipsum dolor.`) } get name() { return this.constructor.name } } throw new CustomError('foo')
quelle