El ES6 designa algunos objetos nativos como subclasificables, por ejemplo, Objeto, Booleano, Error, Mapa, Promesa, etc. La forma en que estas construcciones se modelan en lib.d.ts hace que sea imposible subclasificar, ya que se definen como un par de una var y una interfaz.
De la sección de especificaciones ES6 19.5.1:
El constructor Error está diseñado para ser subclasable. Puede usarse como el valor de una cláusula de extensión de una declaración de clase. Los constructores de subclase que pretenden heredar el comportamiento de Error especificado deben incluir una super llamada al constructor de Error para inicializar las instancias de subclase.
Actualmente, esto daría como resultado el error "Una clase solo puede extender otra clase":
class NotImplementedError extends Error {
constructor() {
super("Not Implemented");
}
}
Este es un problema general para cualquier biblioteca js que expone funciones que están destinadas a ser subclasificables. Si mi biblioteca exporta el constructor de Foo y espera recibir instancias de subclases de Foo (no solo objetos que implementan una interfaz similar a Foo), actualmente no hay forma de permitir eso.
Me gustaria poder decir
class Error;
No se emitiría javascript para tal declaración, solo una actualización de la tabla de símbolos de Typecript.
Para el caso general, me gustaría poder reemplazar el cuerpo de cualquier declaración de clase con un punto y coma, permitiendo cosas como
class Foo<X, Y> extends Bar<X> implements Baz<Y>;
lo que significaría que la biblioteca ya garantiza que Foo.prototype es una instancia de Bar.prototype e implementa la interfaz Baz.
@metaweta creo que puede hacer algunas redundancias:
interface Foo {
}
class Foo; // Foo is now a class!
interface Bar extends Foo {
}
class Bar extends Foo; // Two `extends Foo`s.
interface X {
}
class X extends Foo; // Hmm?
interface Y extends Foo {
}
class Y; // Hmm?
Todavía tiene algunas posibilidades, ya que las interfaces subclasables funcionarán como clases abiertas. N.º 819
@metaweta, su primer caso debe ser manejado por una declaración de clase ambiental. p.ej
// myLib.d.ts
declare class Error {
}
// no code emitted here for this.
// myfile.ts
// Error is subclassable,
class MyError extends Error {
}
Para el segundo caso, presentaría una sugerencia diferente.
Aquí está la lista completa de objetos "subclasables" de la especificación ES6. actualmente estos están todos definidos como pares interfaz / var.
Problemas:
Soluciones posibles:
@mhegazy Gracias, no estaba al tanto de la construcción de declaración de clase ambiental.
Cuando extiendo la clase Error de esta manera (usando la definición de clase ambiental), lanzar ExtendedError no produce un seguimiento de pila ni asigna el mensaje correctamente.
declare class Error {
constructor(message?: string);
}
class ExtendedError extends Error {
constructor(message?: string) {
super(message + " extended");
}
}
//throw new Error("Test");
throw new ExtendedError("Test");
@unional, esto parece un problema de motor. según la especificación ES6 debería funcionar. Los motores deberían arreglarlos ahora que ES6 se ha ratificado.
Me las arreglé para que funcionara. En mi código js que estaba funcionando, tengo la llamada Error.captureStackTrace pero la elimino cuando la implemento en ts porque la declaración de Error no la tiene.
Hay un código de ejemplo:
Es una excepción similar a C # que toma una innerException.
declare class Error {
public name:string;
public message:string;
public stack:string;
constructor(message?:string);
static captureStackTrace(error: Error, constructorOpt: any);
}
class Exception extends Error {
public innerException: Error;
constructor(message?: string, innerException?: Error|string) {
// Guard against throw Exception(...) usage.
if (!(this instanceof Exception)) return new Exception(message, innerException);
super();
if (typeof Error.captureStackTrace === 'function') {
//noinspection JSUnresolvedFunction
Error.captureStackTrace(this, arguments.callee);
}
this.name = "Exception";
if (innerException) {
if (innerException instanceof Error) {
this.innerException = innerException;
this.message = message + ", innerException: " + this.innerException.message;
}
else if (typeof innerException === "string") {
this.innerException = new Error(innerException);
this.message = message + ", innerException: " + this.innerException.message;
}
else {
this.innerException = innerException;
this.message = message + ", innerException: " + this.innerException;
}
}
else {
this.message = message;
}
}
}
Corregido por # 3516. Las clases ahora pueden extender expresiones arbitrarias de tipos de funciones constructoras.
¿Qué versión de TypeScript se enviará con esta corrección?
Revisé rápidamente las etiquetas de la versión 1.5.3 y 1.5.4, y parece que aún no se ha enviado, solo en la versión maestra por ahora.
EDITAR:
Lo siento, ahora mismo he notado que el error marcado por el hito "TypeScript 1.6"
¡Gracias por tu trabajo!
@kostrse , puede probar nuestras versiones nocturnas de TypeScript 1.6 ejecutando npm install -g typescript@next
.
Hola,
Estoy usando TypeScript 1.6.2 y mi lib.es6.d.ts muestra Error (y Array
¿Esto ya está arreglado en 1.6.2?
¡Salud!
@jpsfs la solución, como señaló @ahejlsberg en https://github.com/Microsoft/TypeScript/issues/1168#issuecomment -112955503, es permitir que las clases extiendan expresiones arbitrarias de tipos de funciones de constructor.
Incluso existe la posibilidad de extender la clase Error
hoy en día, sigo teniendo inconvenientes con ella en el nodo. Por ejemplo, tengo problemas con "error.stack". Cuando hago throw new Error(...)
obtengo error.stack
, pero cuando hago throw new CustomError()
- no lo hago. Para solucionarlo me obligué a usar este truco:
export class HttpError extends Error {
httpCode: number;
message: string;
constructor(httpCode: number, message?: string) {
super();
if (httpCode)
this.httpCode = httpCode;
if (message)
this.message = message;
this.stack = new Error().stack;
}
}
Comentario más útil
Incluso existe la posibilidad de extender la clase
Error
hoy en día, sigo teniendo inconvenientes con ella en el nodo. Por ejemplo, tengo problemas con "error.stack". Cuando hagothrow new Error(...)
obtengoerror.stack
, pero cuando hagothrow new CustomError()
- no lo hago. Para solucionarlo me obligué a usar este truco: