Skip to content

Instantly share code, notes, and snippets.

@Shoghy
Last active July 22, 2024 04:36
Show Gist options
  • Save Shoghy/a4fc4c1075a2fdcf1f090a921c34c625 to your computer and use it in GitHub Desktop.
Save Shoghy/a4fc4c1075a2fdcf1f090a921c34c625 to your computer and use it in GitHub Desktop.
A typescript try/catch with type aware catchs.
export type Func<P extends Array<unknown>, R> = (...args: P) => R;
interface JSTypes{
string: string
number: number
bigint: bigint
boolean: boolean
symbol: symbol
undefined: undefined
object: object
function: Func<any, unknown>
}
class Catcher<T>{
func: () => T;
error?: unknown;
success?: T;
protected errorCatched: boolean;
protected awaiting: boolean;
protected lateCatchsCalls: Array<Func<[], void>>;
protected awaitingPromise?: Promise<void>;
protected catchPromise?: Promise<unknown>;
protected lateFinally?: () => Promise<void> | void;
constructor(func: () => T){
this.func = func;
this.errorCatched = false;
this.awaiting = false;
this.lateCatchsCalls = [];
this.execute();
}
protected async asyncExecute(){
try{
this.success = await this.success;
}catch(e){
this.error = e;
}
this.awaiting = false;
for(const late of this.lateCatchsCalls){
late();
if(this.errorCatched) break;
}
if(this.lateFinally){
this.lateFinally();
}
this.lateCatchsCalls = [];
}
execute(){
this.success = undefined;
this.error = undefined;
this.errorCatched = false;
this.awaitingPromise = undefined;
this.lateFinally = undefined;
try{
this.success = this.func();
if(this.success instanceof Promise){
this.awaiting = true;
this.awaitingPromise = this.asyncExecute();
}
}catch(e){
this.error = e;
}
return this;
}
catch<ET>(type: new (...args:any) => ET, func: (error: ET) => unknown): Catcher<T>;
catch<ET extends keyof JSTypes>(type: ET, func: (error: JSTypes[ET]) => unknown): Catcher<T>;
catch(func: (error: unknown) => unknown): Catcher<T>;
catch(type: any, func: any = null){
if(this.awaiting){
this.lateCatchsCalls.push(() => this.catch(type, func));
return this;
}
if(!this.error) return this;
if(this.errorCatched) return this;
const typeofType = typeof type;
if(typeofType === "string"){
if(typeof this.error === type){
this.errorCatched = true;
this.catchPromise = func(this.error);
}
return this;
}else if(typeofType === "function" && func === null){
this.errorCatched = true;
this.catchPromise = type(this.error);
return this;
}
if(this.error instanceof type){
this.errorCatched = true;
this.catchPromise = func(this.error);
}
return this;
}
async wait(){
await this.awaitingPromise;
await this.catchPromise;
}
finally<FT>(func: (error: unknown) => FT){
if(this.awaiting){
this.lateFinally = () => this.finally(func);
return this.wait();
}
func(this.error);
}
throw(){
if(this.awaiting){
this.lateCatchsCalls.push(() => this.throw());
return this.wait();
}
if(!this.error) return this.wait();
if(this.errorCatched) return this.wait();
throw this.error;
}
}
export function tryer<T>(func: () => T){
return new Catcher(func);
}
import { tryer } from "./utils/catcher";
class CustomError extends Error{}
tryer(() => {
throw new CustomError("Creating custom error");
})
.catch(ErrorEvent, (e) => {
/**
* This catch will not be executed
*/
console.log("Error Event");
console.log(e);
})
.catch(CustomError, (e) => {
/**
* This catch will be executed
*/
console.log("Custom Error");
console.log(e);
})
.catch(Error, (e) => {
/**
* Even though this catch is also right will not
* be executed, because just one catch gets executed
*/
console.log("Error");
console.log(e);
})
.finally(() => {
console.log("This will always be executed");
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment