Your function should receive an object as its only argument and return an object with the same properties, but with type validation added. Types should be validated when:
The type validation should always be based on the last part of the property name. For example, age_int property should always be an integer and throw an error when set to something else
Here are possible types:
Assumptions
Examples
Your function should behave as shown below:
const obj= {
age_int: 2,
name_string:"John",
Job: null,
}
const validatingbject=typeCheck(obj)
validatingobject.age_int=2.25 // Throws error
validatingbject.age.int= 2
validatingoject.job="fireman"
validatingbject.address_string= 20 // Throws error
const obj_2= {employed_bool: "true",}
const validatingobject = typeCheck(obj_2) // Throws error
I tried the code below but was unsuccessful.
function typeCheck(object) {
console.log(Object.entries(object));
Object.entries(object).forEach(([key, value]) => {
let type = key.split('_').pop();
let typecheck;
console.log("type:", type);
if (type === "float" || type === "int" || type === "number") {
typecheck = "number";
} else if (type === "bool") {
typecheck = "boolean";
} else if (type === "string") {
typecheck = "string";
}
if (typeof value == typecheck) {
return true;
} else {
console.error("error")
}
});
}
const obj = {
age_int: 2,
name_string: "John",
Job: null,
}
const validatingbject = typeCheck(obj);
typeof value == typecheck, should have parenthesis, to make it clear how it behave:
typeof "string" == 33 // false
typeof ("string" == 33) // 'boolean'
(typeof "string") == 33 // false
Be careful on your split, it doesn't error if no underscore is present:
"age".split('_').pop(); // "age"
"age_int".split('_').pop(); // "int"
"int".split('_').pop(); // "int" <-- this may throw you off
Check that you have an _ underscore with a valid type ("int", "string", any of your custom types) for each key. If not, you skip the iteration.
Maybe you want to use throw new Error("message"), if you want to stop program execution.
Your code does seem to work as you expect it to, if you fix the split issue.
Just in case, maybe you are looking for Typescript, class-validator, or yup (or any equivalent).
Edit: I see you also want an object to be returned const validatingbject=typeCheck(obj), but typecheck function contain no return statement.
If you want validatingobject.age_int=2.25 to error, you first need to have a setter ... here you go this should help you:
function validateTypeOrThrow(e, type) {
if (type === 'int' && !Number.isInteger(e)) {
throw new Error(`${e} is not a ${type} !`);
}
}
const obj = {};
obj._age_int = 33; // initial value
// _age_int starting with underscore is convention for private
Object.defineProperty(obj, 'age_int', {
set(value) {
// this will infinite loop
// this.age_int = value;
this._age_int = value;
},
get () {
// this will infinite loop
// return this.age_int;
validateTypeOrThrow(this._age_int , 'int');
return this._age_int;
},
});
console.log(obj.age_int);
obj.age_int = 22;
console.log(obj.age_int)
obj.age_int = 'str'; // no error
console.log(obj.age_int) // error
Here is the solution Using includes()
function typeCheck(object) {
for (key in object) {
if (key.includes('string')) {
console.log(object[key]);
if (typeof(object[key]) != 'string') {
throw Error;
}
} else if (key.includes('int') || key.includes('float') || key.includes('number')) {
console.log(object[key]);
if (typeof(object[key]) != 'number') {
throw Error;
} else if (key.includes('int')) {
if (Number.isInteger(object[key])) {
console.log("true");
} else {
throw Error;
}
} else if (key.includes('float')) {
if (Number.isInteger(object[key])) {
throw Error;
} else {
console.log("true");
}
}
} else if (key.includes('bool')) {
if (typeof(object[key]) != 'boolean') {
throw Error;
}
} else if (typeof(object[key] == 'object')) {
console.log('object' + " " + object[key]);
} else {
return object;
}
}
return object;
}
const obj = {
age_int: 23,
name_string: "name",
age_float: 22.4,
Job: null,
}
const validatingbject = typeCheck(obj);
console.log(validatingbject);
validatingbject.job = "fireman";
validatingbject.age_int = 2.25;
typeCheck(obj);
const obj_2 = {
employed_bool: "true",
}
validatingbject = typeCheck(obj_2)
function isInt(n) {
return Number(n) === n && n % 1 === 0;
}
function isFloat(n) {
return Number(n) === n && n % 1 !== 0;
}
function isString(s) {
return typeof s === "string";
}
function isBoolean(val) {
return "boolean" === typeof val;
}
function isNum(n) {
return typeof n === "number";
}
function checktype(key, value, typeMap) {
if (typeMap[key]) {
if (typeMap[key] === "string") {
if (!isString(value)) throw new Error("String Error");
}
if (typeMap[key] === "number") {
if (!isNum(value)) throw new Error("Num Error");
}
if (typeMap[key] === "float") {
if (!isFloat(value)) throw new Error("Float Error");
}
if (typeMap[key] === "int") {
if (!isInt(value)) throw new Error("Int Error");
}
if (typeMap[key] === "bool") {
if (!isBoolean(value)) throw new Error("Boolean Error");
}
}
}
function typeCheck(obj) {
var result = {};
var keys = {};
Object.keys(obj).forEach((o) => {
let val = o.split("_");
val = val[val.length - 1];
keys[o] = val;
});
for (const key in obj) {
var value = obj[key];
Object.defineProperty(result, key, {
enumerable: true,
configurable: true,
set(nv) {
checktype(key, nv, keys);
value = nv;
},
get() {
return value;
},
});
}
return result;
}