bigint-lib
v1.1.0
Published
Use BigInt in library code, whether native or polyfilled
Downloads
9
Readme
bigint-lib
Use BigInt in library code, whether native or polyfilled.
Installation
npm install --save bigint-lib
Usage
If polyfilling, polyfill BigInt
first.
Then,
import {bigIntLib} from "bigint-lib";
/**
* `true` if natively supported; `false` otherwise
*/
bigIntLib.isNativelySupported();
/**
* `true` if considered a `BigInt`
*/
bigIntLib.isBigInt(x);
/**
* Creates a `BigInt` instance
*/
bigIntLib.BigInt(0);
See API for more details
Since this library is meant for library authors, reading the source code to understand how it works internally is recommended.
Motivation
Not all browsers support BigInt
natively.
https://caniuse.com/#feat=mdn-javascript_builtins_bigint
Application code can use polyfills for BigInt
easily.
https://github.com/GoogleChromeLabs/jsbi
However, libraries cannot assume that BigInt
is natively supported, or polyfilled.
A library has to check.
If it is natively supported, we can use BigInt
and all built-in operations directly.
If it is polyfilled, we cannot assume the shape of the exposed API for built-in operations.
Is addition done with x.add(y)
? Or Polyfill.add(x, y)
? Or x.plus(y)
? Is it even implemented at all?
What about every other operation?
This library provides a unified API for all built-in BigInt
operations,
regardless of whether BigInt
is natively supported, or polyfilled.
How it works
This library's only dependency is jsbi
.
We have three cases to handle,
BigInt
is natively supportedWe use the built-in operations directly.
This is the most efficient.
See src/native.ts for more details.
BigInt
is polyfilled usingjsbi
We use
jsbi
for built-in operations.This is still pretty efficient.
See src/jsbi-polyfill.ts for more details.
BigInt
is polyfilled using some other libraryWe convert the other library's
BigInt
toJSBI
, usejsbi
for built-in operations, and convert the result back to the other libary'sBigInt
.This is the least efficient, but saves us from having to worry about the exposed API of the other library.
See src/non-jsbi-polyfill.ts for more details.
Expected Polyfill
This library assumes polyfills conform to some minimal API.
Polyfill with JSBI
To polyfill using jsbi
,
import JSBI from "jsbi";
global.BigInt = JSBI.BigInt;
At the moment, using jsbi
+TypeScript with esModuleInterop:false
may cause the import to fail during run-time.
You may set esModuleInterop:true
to fix the problem.
However, setting esModuleInterop:true
may cause other imports to fail.
You may choose to keep esModuleInterop:false
and change the import to,
import {JSBI} from "bigint-lib/dist/jsbi";
global.BigInt = JSBI.BigInt;
Polyfill with Other Library
If polyfilling with some other library, the library must, minimally, have the following API,
class MyPolyfill {
constructor (mixed : any) {
//snip https://tc39.es/ecma262/#sec-bigint-constructor
}
toString () {
return //snip base-10 string
}
}
global.BigInt = (mixed : any) => new MyPolyfill(mixed);
The polyfill must also satisfy the following properties,
BigInt(0) instanceof MyPolyfill
> true
Object.getPrototypeOf(BigInt(0)).constructor === MyPolyfill
> true
API
The following are exported by this library,
BigIntLib
is the unified API, for native and polyfilledBigInt
operations.getBigIntLib()
returns an instanceofBigIntLib
, depending on whetherBigInt
is native or polyfilled. See How it works for more details.JSBI
is a re-export ofjsbi
bigIntLib
is of typeBigIntLib
and is initialized withgetBigIntLib()
whenbigint-lib
is first imported.biLib
is a synonym forbigIntLib
; in casebigIntLib
is too verbosenativeBigIntLib
is aBigIntLib
instance that assumesBigInt
is natively supported.jsbiPolyfillBigIntLib
is aBigIntLib
instance that assumesBigInt
is polyfilled withjsbi
.getNonJsbiPolyfillBigIntLib()
returns aBigIntLib
instance that assumesBigInt
is polyfilled with some other library.getNativeOrJsbiPolyfillBigIntLib()
returns anativeBigIntLib
orjsbiPolyfillBigIntLib
, depending on whetherBigInt
is natively supported or polyfilled.nativeOrJsbiLib
is aBigIntLib
instance and is initialized withgetNativeOrJsbiPolyfillBigIntLib()
whenbigint-lib
is first imported.
BigIntLib
The interface is mostly the same as jsbi
's
| Operation | native BigInt
| bigint-lib
| Note
|---|---|---|---|
|Creation from String | a = BigInt("456")
| a = biLib.BigInt("456")
|Creation from Number | a = BigInt(789)
| a = biLib.BigInt(789)
|Creation from BigInt | a = BigInt(a)
| a = biLib.BigInt(a)
|Conversion to String | a.toString(radix)
| biLib.toString(a, radix)
| radix
defaults to 10
; must be in [2, 36]
|Conversion to Number | Number(a)
| biLib.toNumber(a)
| May result in precision loss
|Truncation | BigInt.asIntN(width, a)
| biLib.asIntN(width, a)
| Throws if width
is negative
| | BigInt.asUintN(width, a)
| biLib.asUintN(width, a)
| Throws if width
is negative
|Type check | typeof a === "bigint"
| biLib.isBigInt(a)
|Native BigInt
check | typeof BigInt(0) === "bigint"
| biLib.isNativelySupported()
| Operation | native BigInt
| bigint-lib
| Note
|---|---|---|---|
|Arithmetic | |
|Unary minus | b = -a
| b = biLib.unaryMinus(a)
|Addition | c = a + b
| c = biLib.add(a, b)
|Subtraction | c = a - b
| c = biLib.subtract(a, b)
|Multiplication | c = a * b
| c = biLib.multiply(a, b)
|Division | c = a / b
| c = biLib.divide(a, b)
| Throws if b
is zero
|Remainder | c = a % b
| c = biLib.remainder(a, b)
| Throws if b
is zero
|Exponentiation | c = a ** b
| c = biLib.exponentiate(a, b)
| Throws if b
is negative
|Bitwise | |
|Left-shift | c = a << b
| c = biLib.leftShift(a, b)
| Allows negative shift
|Signed right-shift | c = a >> b
| c = biLib.signedRightShift(a, b)
| Allows negative shift
|Bitwise NOT | b = ~a
| c = biLib.bitwiseNot(a)
|Bitwise AND | c = a & b
| c = biLib.bitwiseAnd(a, b)
|Bitwise OR | c = a \| b
| c = biLib.bitwiseOr(a, b)
|Bitwise XOR | c = a ^ b
| c = biLib.bitwiseXor(a, b)
|Comparison | a == b
| biLib.equal(a, b)
| | a != b
| biLib.notEqual(a, b)
| | a < b
| biLib.lessThan(a, b)
| | a <= b
| biLib.lessThanOrEqual(a, b)
| | a > b
| biLib.greaterThan(a, b)
| | a >= b
| biLib.greaterThanOrEqual(a, b)
|Unsupported | |
|Literals | a = 123n
| N/A
|Increment | a++
/++a
| N/A
| | a + 1n
| biLib.add(a, biLib.BigInt(1))
|Decrement | a--
/--a
| N/A
| | a - 1n
| biLib.subtract(a, biLib.BigInt(1))
nativeOrJsbiLib
If global.BigInt
is natively supported, returns nativeBigIntLib
.
Otherwise, returns jsbiPolyfillBigIntLib
.
This is useful for libraries that need to perform many complex
BigInt
operations before returning a result.
import {bigIntLib, nativeOrJsbiLib} from "bigint-lib";
const my1 = nativeOrJsbiLib.BigInt(1);
//Takes native or JSBI polyfilled bigints
//Will return a native or JSBI polyfilled bigint
function myComplexFunctionImpl (m : bigint, n : bigint) : bigint {
if (nativeOrJsbiLib.equal(m, 0)) {
return nativeOrJsbiLib.add(n, my1);
}
if (nativeOrJsbiLib.equal(n, 0)) {
return myComplexFunctionImpl(
nativeOrJsbiLib.subtract(m, my1),
my1
);
}
return myComplexFunctionImpl(
nativeOrJsbiLib.subtract(m, my1),
myComplexFunctionImpl(m, nativeOrJsbiLib.subtract(n, 1))
);
}
//Takes native, JSBI polyfilled, or other polyfilled bigints
//Must return a `bigint` that may be native, polyfilled with JSBI, or polyfilled with other libraries
function myComplexFunction (m : bigint, n : bigint) : bigint {
//Will be a native or JSBI polyfilled `bigint`
const myM = nativeOrJsbiLib.BigInt(m.toString());
const myN = nativeOrJsbiLib.BigInt(n.toString());
const myResult = myComplexFunctionImpl(myM, myN);
//Convert the result to a `bigint` type the same as its input
return bigIntLib.BigInt(myResult.toString());
}
Using nativeOrJsbiLib
saves the time needed to convert between JSBI and other polyfill libraries,
if other polyfill libraries are used.
Polyfilling with node
- Have your polyfill code in a
.js
file. node -r my-polyfill.js my-entry-point.js
Polyfilling with ts-node
- Have your polyfill code in a
.ts
file. ts-node -r my-polyfill.ts my-entry-point.ts
Development
git clone https://github.com/AnyhowStep/bigint-lib.git
npm install
npm run sanity-check
to build and run tests.npm run
to see a list of commands.