Skip to content

Instantly share code, notes, and snippets.

@dSalieri
Last active December 1, 2023 07:44
Show Gist options
  • Save dSalieri/25887b224dceffe2c97058705420ef77 to your computer and use it in GitHub Desktop.
Save dSalieri/25887b224dceffe2c97058705420ef77 to your computer and use it in GitHub Desktop.
Реализация специального объекта с определением типов данных

Цель: Расширить определение типов данных / Сделать работу с типами более гибкими

const Type = {
of(arg, type = "main") {
if (!["basic", "main", "complex"].some((v) => v === type)) {
throw Error("type argument has incorrect value");
}
const basic = this.isObject(arg) ? "object" : "primitive";
if (type === "basic") return basic;
const main = Object.prototype.toString.call(arg).slice(8, -1).toLowerCase();
if (type === "main") return main;
/// Assert: type === "complex"
return `${basic} ${main}`;
},
ofFunction(arg) {
if (typeof arg !== "function") return null;
const str = Function.prototype.toString.call(arg);
const parsed = str.slice(0, str.indexOf("("));
if (parsed.includes("class")) return "class";
if (parsed.includes("function")) return "function";
if (arg.name.length > 0 && parsed.includes(arg.name)) return "method";
return "arrow"
},
ofPropertyDescriptor(obj, prop) {
const desc = Object.getOwnPropertyDescriptor(obj || {}, prop);
if (!desc) return;
const slots = {
value: Object.prototype.hasOwnProperty.call(desc, "value"),
writable: Object.prototype.hasOwnProperty.call(desc, "writable"),
get: typeof desc.get === "function",
set: typeof desc.set === "function",
};
switch (true) {
case slots.value || slots.writable: {
return "data";
}
case slots.get && slots.set: {
return "accessor";
}
case slots.get: {
return "accessor:get";
}
case slots.set: {
return "accessor:set";
}
}
},
isNumber(arg) {
return typeof arg === "number";
},
isFloat(arg) {
if (!this.isNumber(arg)) return false;
return String(arg).includes(".");
},
isInteger(arg) {
return Number.isInteger(arg);
},
isString(arg) {
return typeof arg === "string";
},
isSymbol(arg) {
return typeof arg === "symbol";
},
isBoolean(arg) {
return typeof arg === "boolean";
},
isNull(arg) {
return arg === null;
},
isUndefined(arg) {
return arg === undefined;
},
isBigInt(arg) {
return typeof arg === "bigint";
},
isNaN(arg) {
return arg !== arg;
},
isInfinity(arg, sign) {
if (sign === "+") return arg === Infinity;
if (sign === "-") return arg === -Infinity;
return [Infinity, -Infinity].some((v) => arg === v);
},
isFunction(arg) {
return typeof arg === "function";
},
isAsync(arg) {
const AsyncFunction = Object.getPrototypeOf(async function(){}).constructor;
return Object.getPrototypeOf(arg).constructor === AsyncFunction;
},
isGenerator(arg) {
const GeneratorFunction = Object.getPrototypeOf(function*(){}).constructor;
return Object.getPrototypeOf(arg).constructor === GeneratorFunction;
},
isAsyncGenerator(arg) {
const AsyncGeneratorFunction = Object.getPrototypeOf(async function*(){}).constructor;
return Object.getPrototypeOf(arg).constructor === AsyncGeneratorFunction;
},
isConstructor(arg, secure = false) {
if (!this.isFunction(arg)) return false;
if (secure === false) {
/// fast, but unsecure
return this.isArrow(arg) || this.isMethod(arg)
? false
: arg.prototype.constructor === arg;
} else {
/// heavy, but secure
try {
new new Proxy(arg, {construct() { return {} }});
} catch (e) {
return false;
}
return true;
}
},
isArrow(arg) {
return this.ofFunction(arg) === "arrow";
},
isMethod(arg) {
return this.ofFunction(arg) === "method";
},
isOrdinary(arg) {
return this.ofFunction(arg) === "function";
},
isClass(arg) {
return this.ofFunction(arg) === "class";
},
isBuiltInFunction(arg) {
if (!this.isFunction(arg)) return false;
return Function.prototype.toString.call(arg).match(/{\s*\[native code\]\s*}$/) !== null;
},
isDataProperty(obj, prop) {
return this.ofPropertyDescriptor(obj, prop) === "data";
},
isAccessorProperty(obj, prop) {
const type = this.ofPropertyDescriptor(obj, prop);
return type && type.includes("accessor");
},
isGetter(obj, prop) {
const type = this.ofPropertyDescriptor(obj, prop);
return ["accessor", "accessor:get"].some((value) => value === type);
},
isSetter(obj, prop) {
const type = this.ofPropertyDescriptor(obj, prop);
return ["accessor", "accessor:set"].some((value) => value === type);
},
isPrimitive(arg) {
return !this.isObject(arg);
},
isObject(arg, isNotAFunction) {
const o = typeof arg === "object" && arg !== null;
if (isNotAFunction === true) return o;
return o || typeof arg === "function";
},
isPrimitiveInObject(arg) {
if (this.isPrimitive(arg)) return false;
switch (this.of(arg)) {
case "number":
case "string":
case "boolean":
case "bigint":
case "symbol": {
return true;
}
default: {
return false
}
}
},
__proto__: {
[Symbol.toStringTag]: "Type",
},
};
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment