|  | 
|  | 1 | + | 
|  | 2 | +class Type extends String { | 
|  | 3 | +	/** | 
|  | 4 | +	 * @constructor | 
|  | 5 | +	 * @param {string} typeName - The type's name, regardless of whether it's an object or a primitive. | 
|  | 6 | +	 * @param {string} [objectType] - If this is an object, the object's name. Falsy for a primitive. | 
|  | 7 | +	 */ | 
|  | 8 | +	constructor(typeName, objectType){ | 
|  | 9 | +		if(!(typeof typeName === "string" || typeName instanceof String)) | 
|  | 10 | +			throw new TypeError("'typeName' must be a string"); | 
|  | 11 | +		typeName = String(typeName); | 
|  | 12 | +		if(objectType){ | 
|  | 13 | +			if(!(typeof objectType === "string" || objectType instanceof String)) | 
|  | 14 | +				throw new TypeError("'objectType' must be a string"); | 
|  | 15 | +			objectType = String(objectType); | 
|  | 16 | +		} | 
|  | 17 | +		 | 
|  | 18 | +		super(typeName); | 
|  | 19 | +		 | 
|  | 20 | +		if(objectType){ | 
|  | 21 | +			this.type = this.object = typeName; | 
|  | 22 | +			this.objectType = objectType; | 
|  | 23 | +		} | 
|  | 24 | +		else{ | 
|  | 25 | +			this.type = this.primitive = typeName; | 
|  | 26 | +		} | 
|  | 27 | +	} | 
|  | 28 | +} | 
|  | 29 | + | 
|  | 30 | +function getToStringTag(obj){ | 
|  | 31 | +	return Object.prototype.toString.call(obj).slice(8, -1); | 
|  | 32 | +} | 
|  | 33 | + | 
|  | 34 | +function is(value){ | 
|  | 35 | +	if(value === void 0) | 
|  | 36 | +		return new Type("undefined"); | 
|  | 37 | +	if(value === null) | 
|  | 38 | +		return new Type("null"); | 
|  | 39 | +	const type = typeof value; | 
|  | 40 | +	if(type === "function") | 
|  | 41 | +		return new Type("function", "Function"); | 
|  | 42 | +	if(type === "object"){ | 
|  | 43 | +		const toStringTag = getToStringTag(value); | 
|  | 44 | +		for(const objectType of ["Boolean","Number","String"]){ | 
|  | 45 | +			if(value instanceof globalThis[objectType]) | 
|  | 46 | +				return new Type(objectType.toLowerCase(), toStringTag); | 
|  | 47 | +		} | 
|  | 48 | +		return new Type(type, toStringTag); | 
|  | 49 | +	} | 
|  | 50 | +	return new Type(type); | 
|  | 51 | +} | 
|  | 52 | + | 
|  | 53 | + | 
|  | 54 | +is.object = (v)=>(v instanceof Object); | 
|  | 55 | +is.primitive = (v)=>!is.object(v); | 
|  | 56 | + | 
|  | 57 | +const typeofTypes = [ | 
|  | 58 | +	/*** primitives ***/ | 
|  | 59 | +	"undefined", | 
|  | 60 | +	"null", | 
|  | 61 | +	"bigint", | 
|  | 62 | +	"symbol", | 
|  | 63 | +	 | 
|  | 64 | +	/*** primitives & objects ***/ | 
|  | 65 | +	"boolean", | 
|  | 66 | +	"number", | 
|  | 67 | +	"string", | 
|  | 68 | +	 | 
|  | 69 | +	/*** objects ***/ | 
|  | 70 | +	//"object", | 
|  | 71 | +	"function", | 
|  | 72 | +]; | 
|  | 73 | +for(const type of typeofTypes){ | 
|  | 74 | +	is[type] = (v)=>(is(v).type === type); | 
|  | 75 | +} | 
|  | 76 | + | 
|  | 77 | +is.number.real = (v)=>(is.number(v) && Number.isFinite(1*v)); | 
|  | 78 | +is.number.infinite = (v)=>(is.number(v) && !Number.isFinite(1*v) && !Number.isNaN(1*v)); | 
|  | 79 | +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). | 
|  | 80 | + | 
|  | 81 | +const otherCommonTypes = [ | 
|  | 82 | +	"Error", | 
|  | 83 | +	"Date", | 
|  | 84 | +	"RegExp", | 
|  | 85 | +	"Array", | 
|  | 86 | +	"Map", | 
|  | 87 | +	"Set", | 
|  | 88 | +	"WeakMap", | 
|  | 89 | +	"WeakSet", | 
|  | 90 | +	"Promise", | 
|  | 91 | +]; | 
|  | 92 | +for(const objectType of otherCommonTypes){ | 
|  | 93 | +	is[objectType.toLowerCase()] = (v)=>(v instanceof globalThis[objectType]); | 
|  | 94 | +} | 
|  | 95 | + | 
|  | 96 | + | 
|  | 97 | + | 
|  | 98 | +export { is as default }; | 
0 commit comments