-
Notifications
You must be signed in to change notification settings - Fork 1
/
errors.ts
144 lines (136 loc) · 5.28 KB
/
errors.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
/* eslint-disable @typescript-eslint/no-misused-new */
import { Numerical } from "./definitions";
/**
* Attaches the prototype of the JavaScript Error object to the given object.
* This approach of creating error types is used over extending the Error class
* because native extends breaks for Error, Array and other native types. Check
* out [this StackOverflow thread](https://stackoverflow.com/questions/1382107/whats-a-good-way-to-extend-error-in-javascript)
* for further reading.
* @param E The constructor like function or object.
* @param name The name of the error type.
* @internal
*/
function setErrorPrototype(E: any, name: string) {
E.prototype = Object.create(Error.prototype, {
constructor: {
value: Error,
enumerable: false,
writable: true,
configurable: true
}
});
Reflect.setPrototypeOf(E, Error);
E.prototype.name = name;
}
/**
* Creates a custom Error type object and passes the given arguments to the
* Error constructor.
* @param thisArg The object to attach the error type to.
* @param args Arguments to pass to the error constructor.
* @see {@link setErrorPrototype}
* @internal
*/
function getErrorObject(thisArg: any, ...args: any[]) {
const instance = Reflect.construct(Error, args);
Reflect.setPrototypeOf(instance, Reflect.getPrototypeOf(thisArg));
return instance;
}
/**
* The error thrown when attempt is made to divide by zero.
*/
export interface DivisionByZero {
/**
* The error thrown when attempt is made to divide by zero.
* @param message The message to show.
*/
new (message: string): DivisionByZero;
}
export const DivisionByZero = <DivisionByZero><unknown> function(this: any, message: string) {
return getErrorObject(this, message);
};
setErrorPrototype(DivisionByZero, "division by zero");
/**
* The error thrown when some sort of [indeterminate form](https://en.wikipedia.org/wiki/Indeterminate_form) is produced during
* calculations.
*/
export interface IndeterminateForm {
/**
* The error thrown when some sort of [indeterminate form](https://en.wikipedia.org/wiki/Indeterminate_form) is produced during
* calculations.
* @param message The message to display.
*/
new (message: string): IndeterminateForm;
}
export const IndeterminateForm = <IndeterminateForm><unknown> function(this: any, message: string) {
return getErrorObject(this, message);
};
setErrorPrototype(IndeterminateForm, "indeterminate form");
/**
* The error thrown when some sort of illegal overwrite is attempted. It is
* usually in the case of trying to define a constant with the same name
* as another previously defined constant.
*/
export interface Overwrite {
/**
* The error thrown when some sort of illegal overwrite is attempted. It is
* usually in the case of trying to define a constant with the same name
* as another previously defined constant.
* @param name The name of the constant which is being overwritten.
*/
new (name: string): Overwrite;
}
export const Overwrite = <Overwrite><unknown> function(this: any, name: string) {
return getErrorObject(this, `A constant with name ${name} has already been declared.`);
};
setErrorPrototype(Overwrite, "overwrite");
/**
* The error thrown when some invalid index of some quantity is being accessed.
* An invalid index would be any index which does not exist on a particular quantity.
*/
export interface InvalidIndex {
/**
* Creates an {@link InvalidIndex} error.
* @param passed The index value being accessed.
* @param start The value from which indexing starts.
*/
new (passed: number, start: number): InvalidIndex;
}
export const InvalidIndex = <InvalidIndex><unknown> function(this: any, passed: number, start: number) {
return getErrorObject(this, `Index ${passed} does not exist. Indexing starts from ${start}.`);
};
setErrorPrototype(InvalidIndex, "invalid index");
/**
* The error thrown when a value is passed to a function for which the function
* value is undefined. This is a better way to handle undefined function values
* than returning an `undefined`.
*/
export interface UndefinedValue {
/**
* The error thrown when a value is passed to a function for which the function
* value is undefined. This is a better way to handle undefined function values
* than returning an `undefined`.
* @param fnName The name of the function called.
* @param value The value passed to the function.
* @param extra Any additional message to display.
*/
new (fnName: string, value: Numerical, extra?: string): UndefinedValue;
}
export const UndefinedValue = <UndefinedValue><unknown>function(this: any, fnName: string, value: Numerical, extra?: string) {
const trail = extra === undefined? "": ` ${extra}`;
return getErrorObject(this, `Function ${fnName} is undefined for input ${value}.${trail}`);
};
setErrorPrototype(UndefinedValue, "undefined value");
/**
* The error thrown when the string form of a number fails to parse.
*/
export interface IllegalNumberFormat {
/**
* The error thrown when the string form of a number fails to parse.
* @param passed The incorrect string form of number passed.
*/
new (passed: string): IllegalNumberFormat;
}
export const IllegalNumberFormat = <IllegalNumberFormat><unknown>function(this: any, passed: string) {
return getErrorObject(this, `Number format failed to parse: ${passed}`);
};
setErrorPrototype(IllegalNumberFormat, "illegal number format");