I'm working on a JavaScript project that would benefit hugely from being able to have some very specific integer types enforced (uint8, int256, int20...). I was tempted to use TypeScript but the more I explore it seems to be a bit of misnomer.
I expect a number of responses along the lines of 'don't use JavaScript'. This is a JS implementation of a spec and thus must conform the to spec. I believe that by enforcing these types I can achieve more robust and readable code. I do wonder if someone can make an argument for why this would not be worth the benefits.
I'm working on a JavaScript project that would benefit hugely from being able to have some very specific integer types enforced (uint8, int256, int20...). I was tempted to use TypeScript but the more I explore it seems to be a bit of misnomer.
I expect a number of responses along the lines of 'don't use JavaScript'. This is a JS implementation of a spec and thus must conform the to spec. I believe that by enforcing these types I can achieve more robust and readable code. I do wonder if someone can make an argument for why this would not be worth the benefits.
Share Improve this question asked Nov 2, 2018 at 7:10 DAnserminoDAnsermino 3831 gold badge5 silver badges18 bronze badges 8- 4 Javascript doesn't have these kinds of types: developer.mozilla/en-US/docs/Web/JavaScript/Reference/…. Typescript can't add them, because it's just a type checker for what already exists in Javascript, it doesn't define a new language. – deceze ♦ Commented Nov 2, 2018 at 7:14
-
I don't think that's possible, unless you use
boolean[]
and helper functions to convert fromnumber
toboolean[]
, as well as operation functions to add, subtract and multiply – ShamPooSham Commented Nov 2, 2018 at 7:17 -
What do you mean by
it seems to be a bit of misnomer
? It's a supertype of JavaScript where type checks are enforced. I'm not sure what you'd expect it to be. – VLAZ Commented Nov 2, 2018 at 7:22 - 2 One good question is: Do you want them to be enforced by the piler or at runtime? – ShamPooSham Commented Nov 2, 2018 at 7:44
-
2
"would benefit hugely from being able to have some very specific integer types enforced" benefit how? What do you want that the language should do for you? JS has mostly 64bit floats, when doing bit-operations, the result is a
int32
and for>>>
it's auint32
.uint8
can be simulated byvalue & 0xFF
andint20
by(value <<12) >> 12
So what do you need? – Thomas Commented Nov 2, 2018 at 7:52
3 Answers
Reset to default 3It is not possible with build-in types so just create a class wrapper with getter and setter for each of your types. Like this:
class Uint8 {
private _value: number;
get value(): number {
return this._value;
}
set value(newValue: number) {
if (newValue < 0 || newValue >255 || Math.round(newValue) !== newValue) return;
this._value = newValue;
}
}
For typical machine bit-sizes, you could use typed arrays.
For example,
const typedArray1 = new Int8Array(8);
typedArray1[0] = 32;
This array will store 8-bit signed integers.
For each integer type, you have a corresponding typed array.
See MDN for more details.
For other bit-sizes, I do not have an easy solution.
Typescript allows numbers to be types, and those types can be bined with a type union:
type uint8 = 0 | 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 | 145 | 146 | 147 | 148 | 149 | 150 | 151 | 152 | 153 | 154 | 155 | 156 | 157 | 158 | 159 | 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | 168 | 169 | 170 | 171 | 172 | 173 | 174 | 175 | 176 | 177 | 178 | 179 | 180 | 181 | 182 | 183 | 184 | 185 | 186 | 187 | 188 | 189 | 190 | 191 | 192 | 193 | 194 | 195 | 196 | 197 | 198 | 199 | 200 | 201 | 202 | 203 | 204 | 205 | 206 | 207 | 208 | 209 | 210 | 211 | 212 | 213 | 214 | 215 | 216 | 217 | 218 | 219 | 220 | 221 | 222 | 223 | 224 | 225 | 226 | 227 | 228 | 229 | 230 | 231 | 232 | 233 | 234 | 235 | 236 | 237 | 238 | 239 | 240 | 241 | 242 | 243 | 244 | 245 | 246 | 247 | 248 | 249 | 250 | 251 | 252 | 253 | 254 | 255;
let works: uint8 = 5;
let doesntWork: uint8 = 2000;
Now those types are only enforced at conpile time, to mitigate this you could use a function that performs a runtime check:
function toUint(n: number): uint8 {
if(!Number.isInteger(n) || n < 0 || n > 255) throw new RangeError("Number is out of Uint8 range");
return n as uint8;
}
const works: uint8 = toUint(Math.random() * 100);
It might get better in the future, there is a proposal to support range types which will beautify the whole thing to:
type uint8 = 0..255;