Meouzer's Playground for ReadMe.md Display
npm install meouzers-playgroundutil.types.isKlass(x) functions is the best option. Our type checkers
Object.prototype.toString(), constructor names,
instanceof with results that simply do not work unless your
new Klass(...). Anyway,
Object.prototype.toString() is a complete mess
type(x) function that correctly types everything.
is.Klass(x) type checkers where Klass is a JavaScript class or
is.node_path_Klass(x) type checkers where
path.
type(x) blows away the competition. Plus it and its compatriots
const x = new Foo() where Foo is a programmer defined class.
x = new Boolean(true).
Object.create(), are so
Boolean.prototype
Object.create(new Boolean(true)) to "Boolean".
Object.create()
Object.prototype
Import for Node
const {type, is} = require('type-quickly')
-------------------------------------------------------------------------
Import for Browser
type="text/javascript">
or copy type-quickly.js anywhere and link to it
-------------------------------------------------------------------------
ES6 classes:
Boolean; Number; String; Date; RegExp; Array; Int8Array; Uint8Array;
Uint8ClampedArray; Int16Array; Uint16Array; Int32Array; Uint32Array;
Float32Array; Float64Array; BigInt64Array; BigUint64Array; Error;
URIError; EvalError; RangeError; ReferenceError; SyntaxError; TypeError;
WeakSet; Set; WeakMap; Map; ArrayBuffer; DataView; Promise;
// Map objects (Map.prototype or objects deriving from it)
const x = new Map();
const prototype = Map.prototype;
const secDegObj = Object.create(x);
// They are correctly typed
type(x) is "Map"
type(prototype) is "Object"
type(secDegObj) is "Object"
is.Map(x) is true
is.Map(prototype) is false
is.Map(secDegObj) is false
-------------------------------------------------------------------------
JavaScript classes beyond ES6 for node and the browser: some were
originally defined in node, in which case they are now global in node.
AggregateError; AbortController; AbortSignal; Blob;
ByteLengthQueuingStrategy; BroadcastChannel; CompressionStream;
CountQueuingStrategy; CryptoKey; DecompressionStream; Event; EventTarget;
FormData; Headers; MessageChannel; MessageEvent; MessagePort;
PerformanceEntry; PerformanceMeasure; PerformanceObserver;
PerformanceObserverEntryList; PerformanceResourceTiming;
ReadableByteStreamController; ReadableStream; ReadableStreamBYOBReader;
ReadableStreamDefaultController; ReadableStreamDefaultReader;
SharedArrayBuffer; TextDecoderStream; TextEncoder; TextEncoderStream;
TransformStream; TransformStreamDefaultController; URL; URLSearchParams;
WritableStream; WeakRef; WritableStreamDefaultController;
WritableStreamDefaultWriter;
const x = new Blob();
type(x) is "Blob" in node and browser
is.Blob(x) is true in node and browser
is.node_buffer_Blob(x) is true in node environment since
Blob is defined at node.buffer.
-------------------------------------------------------------------------
Node Environment only. Node classes that are not JavaScript globals.
const fs = require('fs');
const x = new fs.WriteStream("dummy.txt");
type(x) is "node_fs_WriteStream"
is.node_fs_WriteStream(x) is true
The is.node_fs_WriteStream() function is not available for the browser.
`
$3
Programmer defined classes are correctly typed out of the box, assuming
the programmer always insures the constructor is correct, i.e.,
Klass.prototype.constructor must be Klass.
However, if you want to make such typing lightning fast, then
there are two typing protocols. Both work even if the constructor is not
properly set.
Protocol-1 is preferable since it at no cost handles edge cases of the
class in the type() and dtype() functions.
#### Protocol-1 for Typing Programmer Defined Classes
For a programmer defined class Klass, simply write
(1) type.asInstance(this, "Klass") inside
the constructor and (2) type.asClass(Klass) outside
the constructor. Edge cases are most excellently
handled.
`
function Klass()
{
// (1) Make sure type() works correctly on Klass objects
type.asInstance(this, "Klass");
}
// If you redefine Klass.prototype, make sure (2)
// succeeds not preceeds it.
Klass.prototype = ...
// (2) Provide an is.Klass() function and make
// sure dtype() handles Klass edge cases.
type.asClass(Klass)
// Klass objects
// (Klass.prototpe and objects derived from it)
const x = new Klass()
const prototype = Klass.prototype
const edgeCase = Object.create(Klass.prototype)
const secDegObj = Object.create(x);
// They are typed correctly.
type(x) is "Klass"
type(prototype) is "Object"
type(edgeCase) is "Object"
type(secDegObj) is "Object"
is.Klass(x) is true
is.Klass(prototype) is false
is.Klass(edgeCase) is false
is.Klass(secDegObj) is false
`
#### Protocol-2 for Typing Programmer Defined Classes
Protocol-2 is deprecated unless protocol-1 is unfeasible
for some odd reason, e.g., there is no access to the inside of the
constructor.
To type a programmer defined class Klass, write
type.thisClass(Klass) outside the constructor.
Edge cases will be incorrectly typed to "Klass".
Edge cases will also be incorrectly handled dtype().
`
function Klass()
{
}
// Make sure Klass objects, except for the edge case
// are type correctly. Again must be written after
// any redefinition Klass.prototype.
type.thisClass(Klass)
// Klass objects
const x = new Klass()
const prototype = Klass.prototype
const edgeCase = Object.create(Klass.prototype)
const secDegObj = Object.create(x);
type(x) is "Klass"
type(prototype) is "Object"
type(edgeCase) is "Klass" (incorrect)
type(secDegObj) is "Object"
is.Klass(x) is true
is.Klass(prototype) is false
is.Klass(edgeCase) is true (incorrect)
is.Klass(secDegObj) is false
`
Exports
| Export | Description |
|------------|----------------------------------------------------------------------------------------------|
| type(x) | Robust and very fast typing function. |
| is | Object whose function properties test for the various data types, amongst other capabilities |
| dtype(x) | See dtype(x) appendix. Programmer classes assume constructor-protocol. |
Properties of the
is Object
| test | description |
|--------------------------------|-------------------------------------------------------------------------------------------|
| non typing ||
| is.configurable(x,prop) | is the property prop of x configurable? returns true if property not existent on x. |
| is.writable(x,prop) | is the property prop of x writable? returns true if property not existent on x. |
| is.enumerable(x,prop) | is the property prop of x enumerable? returns false if property not existent on x. |
| is.ownProperty(x,p) | is p a property directly defined on x? |
| is.nodeEnvironment() | is running in Node.js as opposed to Browser? |
| is.browserEnvironment() | is running in Browser as opposed to Node.js? |
| is.nativeCode(func) | is func a built-in JavaScript function or method?
(built-ins have native code) |
| typing ||
| is.hostObject(x) | is x a window, document, or DOM object? |
| is.domObject(x) | is x a document or DOM object? |
| is.nullObject(x) | is x a null-object? |
| is.arguments(x) | is x a function's arguments list? |
| is.classPrototype(x) | is x a class prototype? |
| is.Object(x) | is x an object? |
| is.primitive(x) | is x a primitive? |
| is.errorVariant(x) | is x a class instance of Error or other variant Error class? |
| is.typedArray(x) | is x a class instance of a typed array class? |
| is.boolean(x) | is x a boolean? |
| is.number(x) | is x a number? |
| is.string(x) | is x a string? |
| is.bigint(x) | is x a bigint? |
| is.symbol(x) | is x a symbol? |
| is.Function(x) | is x a function? |
| is.mapIterator(x) | is x a Map iterator? |
| is.setIterator(x) | is x a Set iterator? |
| is.generatorFunction(x) | is x a generator function? |
| is.generatorObject(x) | is x a generator object? |
| is.asyncFunction(x) | is x an async function? |
| is.arrayBufferView(x) | ??????? |
| is.Klass (x) | is x a class instance of Klass? Klass may be a built-in or programmer defined class. |
| is.node\_abc\_..._Klass(x) | is x a class instance of the node class whose complete path is node\_abc\_..._Klass? |
Note the difference between is.boolean(x) and is.Boolean(x), which check for
the primitive boolean and class instance of Boolean respectively.
Concerning is.ownProperty(x,p), this function works correctly even if x is a null-object.
x.hasownProperty(p) fails if x is a null-object because hasOwnProperty is defined on
Object.prototype from which x does not inherit.
Appendices
The definitive typing Function
dtype(x)
This typing function gives the most detail possible by describing the inheritance chain of x.
Again it is the responsibility of the programmer to follow constructor protocol by
making sure Klass.prototype.constructor is Klass for each programmer defined class Klass.
|Expression|Meaning|
|---|---|
|x is a Klass-object of degree n|x is n steps away from Klass.prototype |
|x is an object of degree n|x is n steps away from Object.prototype|
|x is a null object of degree n|x does not inherit from Object.prototpe and is n steps away from null|
Of course, stepping is done in the inheritance chain of x.
|dtype(x)|x|
|---|---|
|"Klass[Prototype]"| x is Klass.prototype|
|"Klass"| x is a class instance of Klass|
|"Klass[Object]"|x is a Klass object of degree 1, but not a class instance of Klass|
|"Klass[Object(n)]"|x is a Klass object of degree n = 2,3,....|
|"Null[Object]"|x is a null-object of degree 1|
|"Null[Object(n)]"|x is a null-object of degree n = 2,3,...|
|"Object[Prototype]"|x is Object.prototpe|
|"Object"| x is an object of degree 1 |
|"Object(n)"| x is an object of degree n = 2,3,... |
Since the inheritance chain of x may contain more than one class prototype,
where classes are to include the imaginary Object class and the imaginary Null class,
the specificity rule applies: dtype(x) is required to be the most informative choice:
the nearest class prototype is used.
If typing protocol-1 is followed, then the edge case is correctly typed
to Klass[Object].
`
const {dtype} = require('type-quickly');
function Klass()
{
}
// make sure constructor protocol is followed: that
// the following is true.
Klass.prototype.constructor === Klass
// Klass objects
const instance = new Klass();
const prototype = Klass.prototype;
const edgeCase = Object.create(Klass.prototype);
const deg2Obj = Object.create(Object.create(Klass.prototype);
const deg3Obj = Object.create(Object.create(instance);
dtype(instance) "Klass"
dtype(prototype) "Klass[prototype]"
dtype(edgeCase) "Klass[Object]" (typing protocol-1 followed)
dtype(edgeCase) "Klass" (incorrect) (typing protocol-1 not followed)
dtype(deg2Obj) "Klass[Object(2)]"
dtype(deg3Obj) "Klass[Object(3)]"
`
Constructor/Protoytpe Apporach to Typing
A constructor/protoytpe approach to typing works as long as programmers make sure their class constructors
are set correctly: Klass.prototype.constructor should be Klass.
A typing function must type class prototypes and all objects deriving from class prototypes correctly.
`
function typeIt(x)
{
if (x === null) return "null";
const tof = typeof(x);
if(tof === 'function')
{
if(x === Function.prototype) return "Object";
return "Function";
}
if (tof !== 'object') return tof;
const proto = Object.getPrototypeOf(x);
if(proto === null) return "Object"
if(proto === BigInt.prototype || proto === Symbol.prototype )
return "Object";
if(x.constructor !== proto.constructor
&& typeof(x.constructor) === "function"
&& x === x.constructor.prototype) return "Object";
const Klass = proto.constructor;
if(Klass === undefined) return "Object";
if(proto === Klass.prototype) return Klass.name;
return "Object";
}
`
The Edge Case
The edge case of a class Klass is edgeCase = Object.create(Klass.prototype)
that isn't to be used as a class prototype itself nor to be modified to become
a class instance of Klass via a call to Klass.call(x,...) or Klass.apply(x,[...]).
No typing function discussed in this readme file correctly types edge cases
of the built-in classes. That's for good reason because edge cases have
no reason for existence in JavaScript, and taking edge cases of built-in classes into
account would slow down code for no good reason. However, we do take edge cases of
programmer defined classes into account because there is no cost to typing
them correctly.
The author's type-robustly package does take edge cases of the built-in classes into account.
If you think edge cases do matter, then type-robustly is your only possible package.
In any case, the dtype() function of type-robustly is great for diagnostics,
as it traces out the inheritance chain, and is in fact used by deep-copy-diagnostics.
Deep copy packages on NPM will make the mistake of copying a class instance into
an edge case and visa-versa. Only use of dtype()` of the type-robustly package