Skip to content

Commit dc241b0

Browse files
committed
- rewritten
- add README
1 parent 5f51b0d commit dc241b0

2 files changed

Lines changed: 135 additions & 71 deletions

File tree

README.md

Lines changed: 85 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,2 +1,85 @@
1-
# javascript-type-testing
2-
Improved JavaScript type testing
1+
# Improved JavaScript Type Testing
2+
A robust alternative to JavaScript's `typeof` keyword.
3+
4+
This is a JavaScript module that exports: [`is`](#is) (default)
5+
6+
---
7+
8+
9+
## Get the type
10+
11+
### is()
12+
13+
The **is()** function determines the type of its argument and returns a [Type](#the-type-class) object.
14+
15+
Syntax:
16+
> `is(value)`
17+
18+
Parameters:
19+
- ***value*** - The value to determine the type of.
20+
21+
Return value:
22+
- A [Type](#the-type-class) object.
23+
24+
### The Type class
25+
26+
The **Type** class extends the **String** class. In addition to storing a type name, its properties reveal whether the tested value was an object or a primitive.
27+
28+
Syntax:
29+
> `new Type(typeName, isPrimitive)`
30+
31+
Parameters:
32+
- ***typeName*** - (string)
33+
- ***isPrimitive*** - (boolean) Optional.
34+
35+
| Property | Type | Description |
36+
| --- | --- | --- |
37+
| .**type** | string | The type name. This is equivalent to the class's string value. |
38+
| .**primitive** | string | If the `isPrimitive` argument was truthy when constructed, this property was set to the type name. Otherwise, it's undefined. |
39+
| .**object** | string | If the `isPrimitive` argument was falsy when constructed, this property was set to the type name. Otherwise, it's undefined. |
40+
41+
### Example
42+
43+
```
44+
let u;
45+
let p = 2;
46+
let o = new Number(3);
47+
48+
is(u).type; // "undefined"
49+
is(p).type; // "number"
50+
is(o).type; // "number"
51+
is(o)+"" // "number"
52+
53+
is(o) == "number"; //true
54+
is(o).primitive === "number"; // false
55+
is(o).object === "number"; // true
56+
```
57+
58+
---
59+
60+
61+
## Test for a type
62+
63+
For each of the type-testing methods, the only parameter is the item to be tested. The return value is a boolean.
64+
65+
**is.primitive()**
66+
**is.object()**
67+
68+
**is.undefined()**
69+
**is.null()**
70+
71+
**is.number()**
72+
**is.number.real()** - This is most likely what you actually want to use when testing for a number.
73+
**is.number.infinite()**
74+
**is.number.NaN()** - Note that JavaScript doesn't correctly treat all undefined forms as `NaN` (e.g., `1/0` and `0**0`).
75+
76+
**is.bigint()**
77+
**is.boolean()**
78+
**is.string()**
79+
**is.symbol()**
80+
**is.array()**
81+
**is.date()**
82+
**is.regexp()**
83+
**is.function()**
84+
85+

isType.mjs

Lines changed: 50 additions & 69 deletions
Original file line numberDiff line numberDiff line change
@@ -1,81 +1,62 @@
1-
/**
2-
* A more robust 'typeof'.
3-
* https://github.com/wizard04wsu/javascript-type-testing
4-
*
5-
*
6-
* For each of the type testing methods, the only parameter is the item to be tested. These methods do not perform coercion.
7-
*
8-
* is(o) - Returns the item's type.
9-
* - NaN is considered its own type (instead of a number), since it essentially represents something that cannot be converted to a number.
10-
* - For objects, the type of the object is given instead of just 'object' (e.g., 'Array').
11-
*
12-
* is.defined(o)
13-
* is.undefined(o)
14-
* is.null(o)
15-
* is.nan(o) - NaN or a Number object with value NaN
16-
*
17-
* is.array(o)
18-
* is.bigint(o)
19-
* is.boolean(o)
20-
* is.date(o)
21-
* is.function(o)
22-
* is.number(o) - excludes NaN
23-
* is.number.infinite(o)
24-
* is.number.nan(o) - same as is.nan(o)
25-
* is.number.real(o)
26-
* is.regexp(o)
27-
* is.string(o)
28-
* is.symbol(o)
29-
*
30-
* is.object(o)
31-
* is.primitive(o)
32-
*
33-
*
34-
* is.noConflict() - Restores 'is' to what it was before this script replaced it.
35-
*/
361

37-
function is(o){
38-
if(o === void 0) return "undefined";
39-
const t = typeof o;
40-
if(t === "object"){
41-
if(o === null) return "null";
42-
let name = Object.prototype.toString.call(o).slice(8, -1);
43-
if(name === "Number" && 1*o !== 1*o) return "NaN";
44-
return name; //object type
2+
const basicTypes = [
3+
"undefined",
4+
"null",
5+
"number",
6+
"bigint",
7+
"boolean",
8+
"string",
9+
"symbol",
10+
"array",
11+
"date",
12+
"regexp",
13+
"function",
14+
];
15+
16+
class Type extends String {
17+
/**
18+
* @constructor
19+
* @param {string} typeName - The type's name, regardless of whether it's an object or a primitive.
20+
* @param {boolean} [isPrimitive] - Is this a primitive value?
21+
*/
22+
constructor(typeName, isPrimitive){
23+
typeName = String(typename);
24+
super(typeName);
25+
this.type = this[ isPrimitive ? "primitive" : "object" ] = typeName;
4526
}
46-
if(o !== o) return "NaN";
47-
return t; //primitive type or "function"
4827
}
4928

50-
function fn(type, eitherCase){
51-
if(eitherCase) return function (o){ return is(o).toLowerCase() === type; };
52-
return function (o){ return is(o) === type; };
29+
function is(value){
30+
if(value === void 0)
31+
return new Type("undefined", true);
32+
if(value === null)
33+
return new Type("null", true);
34+
const type = typeof value;
35+
if(type === "function")
36+
return new Type("function", false);
37+
if(type === "object"){
38+
const deepType = Object.prototype.toString.call(o).slice(8, -1).toLowerCase();
39+
if(deepType.match(new RegExp(`^${basicTypes.join("|")}$`, "ui")))
40+
return new Type(deepType, false);
41+
return new Type(type, false);
42+
}
43+
return new Type(type, true);
5344
}
5445

55-
is.undefined = function (o){ return o === void 0; };
56-
is.defined = function (o){ return o !== void 0; };
57-
is.null = function (o){ return o === null; };
58-
59-
is.nan = fn("NaN"); //NaN or a Number object with value NaN
60-
//Note that JavaScript doesn't correctly treat all undefined forms as NaN (e.g., 1/0 and 0**0).
46+
function fn(type){
47+
return (v)=>(is(v).type === type);
48+
}
6149

62-
is.array = fn("Array");
63-
is.bigint = fn("bigint");
64-
is.boolean = fn("boolean", true);
65-
is.date = fn("Date");
66-
is.function = fn("function");
67-
is.number = fn("number", true); //excludes NaN
68-
is.number.nan = is.nan;
69-
is.regexp = fn("RegExp");
70-
is.string = fn("string", true);
71-
is.symbol = fn("symbol");
50+
is.primitive = (v)=>(is(v).primitive !== void 0);
51+
is.object = (v)=>(is(v).object !== void 0);
7252

73-
const infinity = 1/0; //Technically, 1/0 is an undefined form, but JavaScript treats it as Infinity.
74-
is.number.infinite = function (o){ return is.number(o) && Math.abs(o) === infinity; };
75-
is.number.real = function (o){ return is.number(o) && Math.abs(o) !== infinity; };
53+
for(const type of basicTypes){
54+
is[type] = fn(type);
55+
}
7656

77-
is.object = function (o){ let t = typeof o; return (t === "object" && o !== null) || t === "function"; };
78-
is.primitive = function (o){ return !is.object(o); };
57+
is.number.real = (v)=>(is.number(v) && Number.isFinite(1*v));
58+
is.number.infinite = (v)=>(is.number(v) && !Number.isFinite(1*v) && !Number.isNaN(1*v));
59+
is.number.NaN = (v)=>(is.number(v) && Number.isNaN(1*v)); //Note that JavaScript doesn't correctly treat all undefined forms as NaN (e.g., 1/0 and 0**0).
7960

8061

8162

0 commit comments

Comments
 (0)