1

TL;DR: Em vez de usar throw usar uniões T|null. Ou para saber exatamente o erro, Either/Result.


Para sinalizar se uma função emite um erro, geralmente eu adoto o paradigma funcional.

Imagine uma função f que divide dois números reais x e y.

f(x, y) = \frac{x}{y} , \text{onde } x, y \in \mathbb{R} , \text{e} y \neq 0

Se apenas deseja saber que o erro aconteceu, geralmente a união simples basta.
O erro é sinalizado no contradomínio da função f : \mathbb{R}^{2} \to \mathbb{R} \cup \{\text{null}\},

function f(x: number, y: number): number | null {
	if (y === 0) return null;
	return x / y;
}

let x: number = 10;
let y: number = 0;
let z: number|null = f(x, y);

if (z == null) {
	console.error("erro");
}

Entretanto se deseja saber especificamente o erro, isto tende a ser um pouco mais verboso.

type DivError = {
	code: 'DIVISION_BY_ZERO';
};

type Result<T, E> =
 | { ok: true; value: T }
 | { ok: false; error: E };

function f(x: number, y: number): Result<number, DivError> {
	if (y === 0) {
		return {
			ok: false,
			error: {
				code: 'DIVISION_BY_ZERO'
			}
		}
	}
	
	return {
		ok: true,
		value: x / y
	}
}

let x: number = 10;
let y: number = 0;
let z = f(x, y);

if (z.ok) {
	console.log(z.value);
	
} else {
	console.error(z.error.code);
}

Para casos simples a primeira abordagem tende a ser o suficiente. Mas a segunda só recomendo em caso de regras de negocio complexas.

Carregando publicação patrocinada...