lang.mjs provides tools essential for all other code. Stuff that should be built into the language.
- Type checks and assertions.
- Terse.
- Performant.
- Minifiable.
- Descriptive.
- Sensible type conversions.
Port and rework of https://github.com/mitranim/fpx.
- #Usage
- #API
- #
function isNil - #
function isSome - #
function isBool - #
function isNum - #
function isFin - #
function isFinNeg - #
function isFinPos - #
function isInt - #
function isNat - #
function isIntNeg - #
function isIntPos - #
function isNaN - #
function isInf - #
function isBigInt - #
function isStr - #
function isSym - #
function isKey - #
function isRecKey - #
function isPk - #
function isJunk - #
function isComp - #
function isPrim - #
function isFun - #
function isFunSync - #
function isFunGen - #
function isFunAsync - #
function isFunAsyncGen - #
function isObj - #
function isDict - #
function isRec - #
function isArr - #
function isTrueArr - #
function isReg - #
function isDate - #
function isValidDate - #
function isInvalidDate - #
function isSet - #
function isMap - #
function isPromise - #
function isIter - #
function isIterAsync - #
function isIterator - #
function isIteratorAsync - #
function isGen - #
function isCls - #
function isList - #
function isSeq - #
function isVac - #
function isScalar - #
function isRef - #
function isEmpty - #
function isInst - #
function opt - #
function req - #
function only - #
function optInst - #
function reqInst - #
function onlyInst - #
function render - #
function renderLax - #
function toTrueArr - #
function deref - #
function reset - #
function is - #
function truthy - #
function falsy - #
function nop - #
function id - #
function val - #
function panic - #
function vac - #
function bind - #
function not - #
function hasOwn - #
function hasOwnEnum - #
function hasInherited - #
function hasMeth - #
function setProto - #
function Emp - #
function show - #
function add - #
function sub - #
function mul - #
function div - #
function rem - #
function lt - #
function gt - #
function lte - #
function gte - #
function neg - #
function inc - #
function dec - #
function round - #Undocumented
- #
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'Links: source; test/example.
True for null and undefined. Same as value == null. Incidentally, these are the only values that produce an exception when attempting to read a property: null.someProperty.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
// Definition
function isNil(value) {return value == null}
l.isNil(null)
// true
l.isNil(undefined)
// true
l.isNil(false)
// falseLinks: source; test/example.
Inverse of #isNil. False for null and undefined, true for other values.
Links: source; test/example.
Same as typeof val === 'boolean'.
Links: source; test/example.
Same as typeof val === 'number'. True if the value is a primitive number, including NaN and ±Infinity. In most cases you should use #isFin instead.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.isNum(1)
// true
l.isNum(`1`)
// false
l.isNum(NaN)
// true <-- WTFLinks: source; test/example.
Same as ES2015's Number.isFinite. True if val is a primitive number and is not NaN or ±Infinity. In most cases you should prefer isFin over isNum.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.isFin(1)
// true
l.isFin(`1`)
// false
l.isFin(NaN)
// falseLinks: source; test/example.
True if the value is finite (via #isFin) and < 0.
Links: source; test/example.
True if the value is finite (via #isFin) and > 0.
Links: source; test/example.
True if the value is an integer: finite via #isFin, without a fractional part.
Links: source; test/example.
True if the value is a natural number: integer >= 0. Also see #isIntPos.
Links: source; test/example.
True if the value is integer < 0. Also see #isFinNeg.
Links: source; test/example.
True if the value is integer > 0. Also see #isNat, #isFinPos.
Links: source; test/example.
Same as ES2015's Number.isNaN. True if the value is actually NaN. Doesn't coerce non-numbers to numbers, unlike global isNaN.
Links: source; test/example.
True if the value is -Infinity or Infinity.
Links: source; test/example.
True if the value is a primitive BigInt. False for all other inputs, including BigInt object wrappers.
Links: source; test/example.
Same as typeof val === 'string'. True if the value is a primitive string.
Links: source; test/example.
Same as typeof val === 'symbol'. True if the value is a primitive symbol.
Links: source; test/example.
True if the value is primitive and usable as a map key. True for all primitives excluding garbage values via #isJunk.
Links: source; test/example.
Short for "is record key".
True if the value qualifies as an object property key: either a string or a symbol.
Uses the term "record" for consistency with #isRec which defines what is a record (a non-iterable object).
Links: source; test/example.
True for objects that implement method .pk which must return a valid #primary key. This interface is used internally by Coll.
Links: source; test/example.
True for garbage values: #nil, #NaN, #±Infinity.
Links: source; test/example.
True if the value is "composite" / "compound" / "complex". Opposite of #isPrim. Definition:
function isComp(val) {return isObj(val) || isFun(val)}Links: source; test/example.
True if the value is a JS primitive: not an object, not a function. Opposite of #isComp.
Links: source; test/example.
Same as typeof val === 'function'. True if the value is any function, regardless of its type (arrow, async, generator, etc.).
Links: source; test/example.
True if the input is a normal sync function. False for generator functions or async functions.
Links: source; test/example.
True if the input is a sync generator function. False for normal sync functions and async functions.
Links: source; test/example.
True if the input is an async non-generator function. False for sync functions, generator functions, or async generator functions.
Links: source; test/example.
True if the input is an async generator function. False for sync functions and async non-generator functions.
Links: source; test/example.
Same as typeof val === 'object' && val !== null. True for any JS object: plain dict, array, various other classes. Doesn't include functions, even though JS functions are extensible objects.
- Compare #
isCompwhich returns true for objects and functions. - For plain objects used as dictionaries, see #
isDict. - For fancy non-list objects, see #
isRec.
Links: source; test/example.
True for a "plain object" created in any of the following ways:
{...someFields}{__proto__: null, ...someFields}Object.create(null)
False for any other input, including instances of any class other than Object, or even for Object.create(Object.create(null)).
See #isRec for a more general definition of a non-iterable object.
Links: source; test/example.
Short for "is record".
True if the value is a non-iterable object. Excludes both #sync_iterables and #async_iterables. Note that #dicts are automatically records, but not all records are dicts.
Technically, promises would qualify as records under this definition. But as a
special case, instances of Promise are excluded to help detect the common
case of forgetting await. The overhead on that check should be virtually
unmeasurable.
Links: source; test/example.
Alias for Array.isArray. Used internally for all array checks.
True if the value is an instance of Array or its subclass. False for all other values, including non-array objects whose prototype is an array.
Links: source; test/example.
Similar to Array.isArray and #isArr, but returns true only for instances of the exact Array class, false for instances of subclasses.
At the time of writing, subclasses of Array suffer horrible performance penalties in V8, and possibly in other engines. Using them can also cause deoptimization of code that would otherwise run much faster. We sometimes prioritize or even enforce "true" arrays for consistent performance.
Links: source; test/example.
True if the value is an instance of RegExp or its subclass.
Links: source; test/example.
True of value is an instance of Date. Most of the time you should prefer #isValidDate.
Links: source; test/example.
True of value is an instance of Date and its timestamp is #finite rather than NaN or Infinity.
Links: source; test/example.
True of value is an instance of Date representing an invalid date whose timestamp is NaN.
Links: source; test/example.
True if the value is an instance of Set or its subclass.
Links: source; test/example.
True if the value is an instance of Map or its subclass.
Links: source; test/example.
True if the value satisfies the ES2015 promise interface.
Links: source; test/example.
True if the value satisfies the ES2015 sync iterable interface. For iterator rather than iterable, use #isIterator.
Links: source; test/example.
True if the value satisfies the ES2015 async iterable interface. For iterator rather than iterable, use #isIteratorAsync.
Links: source; test/example.
True if the value satisfies the ES2015 sync iterator interface. For iterable rather than iterator, use #isIter.
Links: source; test/example.
True if the value satisfies the ES2015 async iterator interface. For iterable rather than iterator, use #isIterAsync.
Links: source; test/example.
True if the value is a #sync_iterator created by calling a generator function.
Links: source; test/example.
True if the input is a function with a prototype, suitable for instanceof checks. False for arrow functions such as () => {}, which don't have a prototype.
Links: source; test/example.
True for any array-like such as: [], arguments, TypedArray, NodeList, etc. Used internally for most list checks. Note that primitive strings are not considered lists.
Links: source; test/example.
True for any of:
Many functions in iter.mjs support arbitrary data structures compatible with values, but some functions such as arr allow only sequences, for sanity checking.
Links: source; test/example.
Short for "is vacuous" or "is vacated". Could also be called "is falsy deep". True if the input is #falsy or a #list where all values are vacuous, recursively. Does not iterate non-lists. Also see complementary function #vac.
Links: source; test/example.
True for a value that could be considered a single scalar, rather than a collection / data structure. Currently this is equivalent to the concept of an intentionally stringable value. In the future, we may consider renaming this function or splitting the concepts.
The following are included:
- Any #primitive except for those which are excluded below.
- Any #object with a special
.toStringmethod, distinct from bothObject.prototype.toStringandArray.prototype.toString. Examples include #dates,URL, and many more.
The following are excluded:
To include nil, use #isScalarOpt.
Links: source; test/example.
Defines a "reference" interface which is consistently across all modules in this library. A "reference" is something that can be #deref into an underlying value. Any object can implement this interface by providing a symbolic property Symbol.for("val").
References are used via the functions #deref and #reset.
The most notable reference types are observables provided by the module obs.
The names deref and reset for this interface are lifted from Clojure.
Combined example:
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
import * as ob from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/obs.mjs'
l.isRef(10) // false
l.isRef({}) // false
const obs = ob.obsRef(10)
l.isRef(obs) // true
l.deref(obs) // 10
l.reset(obs, 20)
l.deref(obs) // 20Links: source; test/example.
True if the input is an empty collection such as list, set, map, or a primitive such as null. False for any other non-primitive. Treating primitives as "empty" is consistent with various functions in iter.mjs that operate on collections.
Links: source; test/example.
Signature: (val, Cls) => bool.
Same as instanceof but does not implicitly convert the operand to an object. True only if the operand is already an instance of the given class. Also unlike instanceof, this is always false for functions.
Links: source; test/example.
Short for "optional". If val is #non_nil, uses #req to validate it. Returns val as-is.
Links: source; test/example.
Signature: (val, test) => val where test: val => bool.
Short for "require". Minification-friendly assertion. If !test(val), throws an informative TypeError. Otherwise, returns val as-is.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.req({one: `two`}, l.isObj)
// {one: `two`}
l.req(`str`, l.isFun)
// Uncaught TypeError: expected variant of isFun, got "str"Links: source; test/example.
Signature: (val, test) => val where test: val => bool.
Type filtering utility. If val satisfies the given test function, returns val as-is. Otherwise returns undefined.
Links: source; test/example.
Short for "optional instance". If val is #non_nil, uses #reqInst to validate it. Returns val as-is.
Links: source; test/example.
Signature: (val, Cls) => val.
Short for "require instance". Asserts that val is an instance of the given class. Returns val as-is.
Links: source; test/example.
Signature: (val, Cls) => val?.
Type filtering utility. If val is an instance of Cls, returns val as-is. Otherwise returns undefined.
Links: source; test/example.
Renders a value for user display. Counterpart to #show, which renders a value for debug purposes. Intended only for #scalar values. Rules:
- #Date with default
.toString→ use.toISOString. This overrides the insane JS default stringification of dates, defaulting to the reversible machine-decodable representation used for JSON. - Other #non-nil #scalars → default JS stringification.
- All other inputs including #nil →
TypeErrorexception.
Links: source; test/example.
Renders a value for user display. Intended only for #scalar values. Unlike #render, this allows nil. Rules:
Links: source; test/example.
Idempotent conversion to a #true array. Allowed inputs:
- #Nil → return
[]. - #True array → return as-is.
- #Iterable → convert to
Array. - Otherwise →
TypeErrorexception.
Links: source; test/example.
Dereferences any #reference. Returns non-references as-is.
See #isRef for a usage example.
See #reset for the opposite operation: writing rather than reading.
Links: source; test/example.
Replaces the current value of any #reference by setting its Symbol.for("val") property.
See #isRef for a usage example.
See #deref for the opposite operation: reading rather than writing.
Links: source; test/example.
Identity test: same as ===, but considers NaN equal to NaN. Equivalent to SameValueZero as defined by the language spec. Used internally for all identity tests.
Note that Object.is implements SameValue, which treats -0 and +0 as distinct values. This is typically undesirable. As a result, you should prefer l.is over === or Object.is unless you know you intend to differentiate -0 and +0.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.is(1, '1')
// false
l.is(NaN, NaN)
// trueLinks: source; test/example.
Same as !! or Boolean. Sometimes useful with higher-order functions.
Links: source; test/example.
Same as !. Sometimes useful with higher-order functions.
Links: source; test/example.
Empty function. Functional equivalent of ; or undefined. Sometimes useful with higher-order functions.
Links: source; test/example.
Identity function: returns its first argument unchanged. Sometimes useful with higher-order functions.
Links: source; test/example.
Takes a value and creates a function that always returns that value. Sometimes useful with higher order functions.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
const constant = l.val(1)
constant()
// 1
constant(`this input is ignored`)
// 1Links: source; test/example.
Same as throw but an expression rather than a statement. Also sometimes useful with higher-order functions.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
const x = someTest ? someValue : l.panic(Error(`unreachable`))Links: source; test/example.
Complements #isVac. Returns undefined if the input is vacuous, otherwise returns the input as-is.
Links: source; test/example.
Like Function.prototype.bind, but instead of taking this as an argument, takes it contextually. By default this is undefined. To set it, use l.bind.call.
Returns a new function that represents partial application of the given function, a common tool in functional programming. When called, it joins arguments from both calls and invokes the original function. Think of it like splitting a function call in two, or more. Performance is inferior to closures; avoid in hotspots.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
const inc = l.bind(l.add, 1)
inc(2)
// 3Note: we don't provide facilities for currying. Experience has shown it to be extremely error prone. Currying, as seen in purely functional languages such as Haskell, tends to care about the amount of arguments. Calling a curried function may either create a new function, or call the underlying function (possibly side-effectful). This approach works reasonably well in statically typed languages, but not in JS where all functions are variadic and it's conventional to sometimes pass extra utility arguments "just in case", which the callee may or may not care about. bind is different because the created function will always call the original function, regardless of how many arguments were passed.
Links: source; test/example.
Returns a new function that negates the result of the given function, like a delayed !.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
function eq(a, b) {return a === b}
const different = l.not(eq)
different(10, 20)
// !eq(10, 20) = true
// equivalent:
function different(a, b) {return !eq(a, b)}Links: source; test/example.
Same as Object.prototype.hasOwnProperty but shorter and safe to call on primitives. Always false for primitives.
Links: source; test/example.
Same as Object.prototype.propertyIsEnumerable but shorter and safe to call on primitives. Always false for primitives.
Links: source; test/example.
Returns true if the target is #non-primitive and has the given property on its prototype. As a consequence, this returns false if the target is a primitive, or has the given property as an "own" property, either enumerable or not.
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.hasInherited([10, 20, 30], `length`)
// false
l.hasInherited([10, 20, 30], `1`)
// false
l.hasInherited([10, 20, 30], `toString`)
// trueLinks: source; test/example.
True if the the given value has the given named method. Safe to call on primitives such as null. Always false for primitives.
Links: source; test/example.
Workaround for bugs related to subclassing.
In some Safari versions, when instantiating a subclass of various recent
built-in classes such as Request/Response/URL, the engine incorrectly
uses the prototype of the superclass rather than the subclass. Occurs in Safari
12-14+, both desktop and mobile. This seems to fix that. Example:
class Abort extends AbortController {
constructor() {
super()
l.setProto(this, new.target)
}
}The following version is shorter but more confusing if you don't know full semantics of JS classes:
class Abort extends AbortController {
constructor() {l.setProto(super(), new.target)}
}Links: source; test/example.
Short for "empty". Hybrid function / superclass for empty objects.
In function mode, Emp() returns Object.create(null), with no measurable overhead. Basically a syntactic shortcut.
Calling new Emp() also returns Object.create(null). This is pointless and should be avoided.
Subclassing Emp creates a class with the cleanest possible .prototype, which is null-based, sharing no common ancestry with anything.
class Empty extends l.Emp {}
Object.getPrototypeOf(Empty.prototype) === null
// Instantiation and inheritance works as expected.
const val = new Empty()
val instanceof Empty
val.constructor === Empty
// `Object` stuff is not inherited.
!(val instanceof Object)
!(`toString` in val)Links: source; test/example.
Renders a value for debug purposes. Counterpart to #render, which renders a value for user display. Convenient for interpolating things into error messages. Used internally in assertion functions such as #req. Approximate rules:
- String → use
JSON.stringify. - Function →
[function ${val.name || val}].- For named functions, this shorter representation is usually preferable to printing the entire source code.
- Object →
- Plain
{}or[]→ useJSON.stringify. - Otherwise
[object <name>], prioritizing constructor name overSymbol.toStringTag.- Exact opposite of default behavior for
Object.prototype.toString.
- Exact opposite of default behavior for
- Plain
- Otherwise → default JS stringification.
Links: source; test/example.
Same as +.
Links: source; test/example.
Same as -.
Links: source; test/example.
Same as *.
Links: source; test/example.
Same as /.
Links: source; test/example.
Same as %.
Links: source; test/example.
Same as <.
Links: source; test/example.
Same as >.
Links: source; test/example.
Same as <=.
Links: source; test/example.
Same as >=.
Links: source; test/example.
Arithmetic negation. Same as unary -.
Links: source; test/example.
Increments by 1.
Links: source; test/example.
Decrements by 1.
Links: source; test/example.
Rounding half away from zero. Has one difference from Math.round: when the number is negative and the fraction is exactly .5, this rounds away from zero. This behavior is more consistent with the default rounding function in many other languages, including Go.
Examples:
import * as l from 'https://cdn.jsdelivr.net/npm/@mitranim/js@0.1.85/lang.mjs'
l.round(-12.5) // -13
l.round(12.5) // 13
Math.round(-12.5) // -12
Math.round(12.5) // 13The following APIs are exported but undocumented. Check lang.mjs.
const VALconst DISPOSEconst ASYNC_DISPOSEfunction reqNilfunction optNilfunction onlyNilfunction reqSomefunction optSomefunction onlySomefunction reqBoolfunction optBoolfunction onlyBoolfunction laxBoolfunction reqNumfunction optNumfunction onlyNumfunction laxNumfunction reqFinfunction optFinfunction onlyFinfunction laxFinfunction reqFinNegfunction optFinNegfunction onlyFinNegfunction reqFinPosfunction optFinPosfunction onlyFinPosfunction reqIntfunction optIntfunction onlyIntfunction laxIntfunction reqNatfunction optNatfunction onlyNatfunction laxNatfunction reqIntNegfunction optIntNegfunction onlyIntNegfunction reqIntPosfunction optIntPosfunction onlyIntPosfunction reqNaNfunction optNaNfunction onlyNaNfunction reqInffunction optInffunction onlyInffunction reqBigIntfunction optBigIntfunction onlyBigIntfunction laxBigIntfunction reqStrfunction optStrfunction onlyStrfunction laxStrfunction isValidStrfunction reqValidStrfunction optValidStrfunction onlyValidStrfunction reqSymfunction optSymfunction onlySymfunction reqKeyfunction optKeyfunction onlyKeyfunction reqRecKeyfunction optRecKeyfunction onlyRecKeyfunction reqPkfunction optPkfunction onlyPkfunction reqJunkfunction optJunkfunction onlyJunkfunction reqCompfunction optCompfunction onlyCompfunction reqPrimfunction optPrimfunction onlyPrimfunction reqFunfunction optFunfunction onlyFunfunction reqFunSyncfunction optFunSyncfunction onlyFunSyncfunction reqFunGenfunction optFunGenfunction onlyFunGenfunction reqFunAsyncfunction optFunAsyncfunction onlyFunAsyncfunction reqFunAsyncGenfunction optFunAsyncGenfunction onlyFunAsyncGenfunction reqObjfunction optObjfunction onlyObjfunction isNpofunction reqNpofunction optNpofunction onlyNpofunction laxNpofunction reqDictfunction optDictfunction onlyDictfunction laxDictfunction reqRecfunction optRecfunction onlyRecfunction laxRecfunction reqArrfunction optArrfunction onlyArrfunction laxArrfunction reqTrueArrfunction optTrueArrfunction onlyTrueArrfunction laxTrueArrfunction reqRegfunction optRegfunction onlyRegfunction reqDatefunction optDatefunction onlyDatefunction reqValidDatefunction optValidDatefunction onlyValidDatefunction reqInvalidDatefunction optInvalidDatefunction onlyInvalidDatefunction reqSetfunction optSetfunction onlySetfunction laxSetfunction reqMapfunction optMapfunction onlyMapfunction laxMapfunction reqPromisefunction optPromisefunction onlyPromisefunction reqIterfunction optIterfunction onlyIterfunction reqIterAsyncfunction optIterAsyncfunction onlyIterAsyncfunction reqIteratorfunction optIteratorfunction onlyIteratorfunction reqIteratorAsyncfunction optIteratorAsyncfunction onlyIteratorAsyncfunction reqGenfunction optGenfunction onlyGenfunction reqClsfunction optClsfunction onlyClsfunction isSubClsfunction reqSubClsfunction reqListfunction optListfunction onlyListfunction laxListfunction reqSeqfunction optSeqfunction onlySeqfunction reqVacfunction optVacfunction onlyVacfunction reqScalarfunction optScalarfunction onlyScalarfunction isScalarOptfunction reqScalarOptfunction optScalarOptfunction onlyScalarOptfunction isArrblefunction reqArrblefunction optArrblefunction onlyArrblefunction isEqablefunction reqEqablefunction optEqablefunction onlyEqablefunction isClearablefunction reqClearablefunction optClearablefunction onlyClearablefunction isErrfunction reqErrfunction optErrfunction onlyErrfunction optReffunction onlyReffunction reqReffunction isArrOffunction reqArrOffunction optArrOffunction isInstOptfunction optOneOffunction reqOneOffunction toInstfunction toInstOptfunction renderOptfunction derefAllfunction resetOptfunction swapfunction Truefunction Falsefunction eqclass Showfunction symPolyconst CLASSESfunction errTypefunction msgTypefunction errFunfunction msgFunfunction throwErrFunfunction errConvfunction errSyntfunction msgConvfunction errConvInstfunction msgConvInstfunction errInstfunction msgInstfunction errInfunction msgInfunction errImplfunction msgImplfunction errTransfunction errWrapfunction errCausefunction errSkipconst WeakRefconst FinalizationRegistryfunction convTypefunction convSyntfunction showFunNamefunction getfunction getOwnfunction reqGetfunction recKeys