|
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 | | - */ |
36 | 1 |
|
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; |
45 | 26 | } |
46 | | - if(o !== o) return "NaN"; |
47 | | - return t; //primitive type or "function" |
48 | 27 | } |
49 | 28 |
|
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); |
53 | 44 | } |
54 | 45 |
|
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 | +} |
61 | 49 |
|
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); |
72 | 52 |
|
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 | +} |
76 | 56 |
|
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). |
79 | 60 |
|
80 | 61 |
|
81 | 62 |
|
|
0 commit comments