In the article The Power of the Simplest Possible Example we implemented the median function per the illustration of the method used to calculate it.
Here we will be adding error handling without using exceptions.
Approach
Error Function Type
Error strings will be created by functions that have the signature:
export type MessageFunctionType = (args?: string[]) => string;
Result Object
We’ll create a class to contain the result and errors if there are any.
/**
* The result of the calculation.
*/
export class Result<E> {
public message?:string
constructor(
public value: E | undefined,
public error?: MessageFunctionType,
public parameters?: string[]
) {
if (error) {
this.message = this.error!(parameters)
}
}
}
In the event of an error the error property is assigned the function of type MessageFunctionType . The error property can be used in a switch statement to select the type of error that occurred.
Errors
We will define two types of errors. The first indicates that no array was passed in to the median
function. The second indicates that one of the values in the array was not a number:
export interface IMedianErrors {
ARRAY_ARGUMENT_NOT_DEFINED: MessageFunctionType;
ARRAY_VALUE_NOT_A_NUMBER: MessageFunctionType;
}
And the implementation for the interface looks like this:
export const MEDIAN_ERRORS: IMedianErrors =
{
ARRAY_ARGUMENT_NOT_DEFINED: (arr?: string[]) => {
return `The array argument for the median function was missing.`;
},
ARRAY_VALUE_NOT_A_NUMBER: (arr?: string[]) => {
return `The array ${ arr && arr.toString() } contains values that are not numbers.`;
}
};
Median Function Implementation
We are now communicating both the result and any errors that occurred using a MedianResult
instance:
/**
* @param arr The set of numbers
*/
export function median(arr?: any[]): MedianResult {
//=============================
// MISSING ARRAY
//=============================
if (!arr) {
const result = new MedianResult(
NaN,
MEDIAN_ERRORS.ARRAY_ARGUMENT_NOT_DEFINED,
[]
);
return result;
}
//=============================
// NON NUMERIC VALUES
//=============================
let numeric = true;
arr &&
arr.forEach((n) => {
if (!isNumeric(n.toString(), {})) {
numeric = false;
}
});
if (!numeric) {
const result = new MedianResult(
undefined,
MEDIAN_ERRORS.ARRAY_VALUE_NOT_A_NUMBER,
arr.map((e) => e.toString())
);
return result;
}
if (!(arr && arr.length)) {
//=============================
// EMPTY ARRAY
//=============================
const result = new MedianResult(undefined);
return result;
} else {
//=============================
// LENGHT OF 1
//=============================
if (arr.length == 1) {
const result = new MedianResult(arr[0]);
return result;
}
//=============================
// PROCESS EVEN OR ODD SET OF NUMBERS
//=============================
const mid = Math.floor(arr.length / 2);
const sorted = [...arr].sort((a, b) => a - b);
const m =
arr.length % 2 !== 0 ? sorted[mid] : (sorted[mid - 1] + sorted[mid]) / 2;
const result = new MedianResult(m);
return result;
}
}