En TypeScript, estoy escribiendo una función que toma una fábrica de Error como argumento: ya sea un nombre de clase o una función de fábrica. Algo como lo siguiente:
// Alias from class-transformer package type ClassConstructor<T> = { new (...args: any[]): T; }; function doSomething(value: number, errorFactory: () => Error | ClassConstructor<Error>) { if (value === 0) { // Zero is not allowed if (/* errorFactory is a class constructor */) { throw new errorFactory() } else { throw errorFactory() } } } En la función anterior, errorFactory puede ser una clase de Error , de modo que funcione el siguiente código:
doSomething(0, Error); O puede ser una función que crea un Error :
doSomething(0, () => new Error()); El problema es que ClassConstructor es un tipo de TypeScript, por lo que no sobrevive a la compilación en JavaScript.
typeof(Error) es function , y también lo es typeof(()=>{}) .
Entonces, ¿cómo determinar el tipo de parámetro? ¿Cuál debería ser la prueba en /* errorFactory is a class constructor */ ?
Por el código anterior, entendí que necesita invocar el constructor con new y la función sin new .
En el ejemplo anterior, Error en realidad se puede invocar sin new , se puede llamar simplemente escribiendo:
throw Error(msg); // msg: string = The error message El siguiente código se puede usar para probar si la función (o constructor) debe llamarse con new :
// Returns: // - True if the 'func' must be called with 'new' // - False if the 'func' can be called without 'new' function isConstructor(func) { try { // Invoke without 'new' func(); } catch (err) { if (/^TypeError:.*?constructor/.test(err.toString())) { // The error is about that it isn't a normal function return true; } else { // The error isn't about that; let's throw it throw new err.constructor(err.toString().substr(err.toString().indexOf(" ") + 1), {cause: err}); } } return false; } // Let's run some tests console.log(isConstructor("abc".constructor)); // False // String() returns empty string; it's not a constructor console.log(isConstructor(() => {})); // False // Arrow function console.log(isConstructor(class {})); // True // This *is* a cliss console.log(isConstructor(Image)); // True // Some built-in cannot be invoked without 'new' console.log(isConstructor(throwErr)); // TypeError: Another error function throwErr() { throw new TypeError("Another error"); }