javascript - Çalışma zamanında fonksiyon ve yapıcıyı ayırt et
TypeScript'te, bir Error fabrikasını argüman olarak alan bir fonksiyon yazıyorum: ya bir sınıf adı ya da bir fabrika fonksiyonu. Aşağıdaki gibi bir şey:
// 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()
}
}
}
Yukarıdaki işlevde, errorFactory bir Error sınıfı olabilir, böylece aşağıdaki kod çalışır:
doSomething(0, Error);
Veya bir Error oluşturan bir fonksiyon olabilir:
doSomething(0, () => new Error());
Sorun, ClassConstructor bir TypeScript türü olduğu için, JavaScript'e derleme sırasında hayatta kalmaması.
typeof(Error) function'dir ve typeof(()=>{}) de öyledir.
Peki bir parametrenin türünü nasıl belirleriz? /* errorFactory bir sınıf yapıcısıdır */ içinde test ne olmalı?
Cevap #1
Yukarıdaki koda göre, yapıcıyı new ile çağırmanız gerektiğini ve fonksiyonu new olmadan çağırmanız gerektiğini anladım.
Yukarıdaki örnekte, Error aslında new olmadan çağrılabilir, sadece yazarak şöyle çağrılabilir:
throw Error(msg); // msg: string = The error message
Aşağıdaki kod, bir fonksiyonun (veya yapıcının) new ile çağrılması gerekip gerekmediğini test etmek için kullanılabilir:
// 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");
}