How to forbid a key from object - javascript

Seems like a no brainer but I can't figure how to add a constraint to forbid the existence of a key in Joi, please how do I do this.
const data = {foo: 'xyz', bar: '123'};
const schema = {
foo: Joi.string(),
// how do i forbid bar
bar: Joi.forbid()
};
const { error } = Joi.object(schema).validate(data)

Use forbidden: https://joi.dev/api/?v=17.4.2#anyforbidden
const schema = {
a: Joi.any().forbidden()
};

you can simple delete the key from the object :
1st Method : delete data.bar
2nd method : {bar,...schema}=data

Related

How to update a schema object, after creation, inside a Joi object?

Wasn't sure the best way to phrase the question, but here is an example of what I am trying to do.
const schema = Joi.Object().keys({
array: Joi.array().length(5)
});
Then after creation I am wanting to update the length method to be a different number.
this.schema.keys({ array: Joi.array().length(8) });
The above code does not work and I'm really just not sure what else to try. (This isn't the only thing I have tried, just where I'm currently at) I've been looking through documentation but haven't found anything helpful for updating a schema. Maybe someone knows of a way to do it?
Any help would be much appreciated!
const Joi = require('joi');
////
// update schema itself.
////
let scheme = Joi.object().keys({
foo: Joi.array().length(5),
});
const a1 = scheme.validate({ foo: [1,2,3,4,5] });
console.log(a1.error); // undefined. valid.
scheme = scheme.keys({
foo: Joi.array().length(8),
});
const a2 = scheme.validate({ foo: [1,2,3,4,5] });
console.log(a2.error); // array.length error occurred.
const a3 = scheme.validate({ foo: [1,2,3,4,5,6,7,8] });
console.log(a3.error); // undefined. vaild.
////
// using base scheme.
////
const base = Joi.object().keys({
foo: Joi.array(),
});
const base_a = base.keys({
foo: Joi.array().length(5),
});
console.log('Using base a1', (base_a.validate({ foo: [1,2,3,4,5]})).error);
const base_b = base.keys({
foo: Joi.array().length(8),
});
console.log('Using base a2', (base_b.validate({ foo: [1,2,3,4,5]})).error);
console.log('Using base a3', (base_b.validate({ foo: [1,2,3,4,5,6,7,8]})).error);
////
// Not good but works.
////
const obj = Joi.object({
foo: Joi.array().length(5),
});
console.log('Obj a1', (obj.validate({ foo: [1,2,3,4,5]})).error);
const merged = Object.assign(obj, Joi.object({
foo: Joi.array().length(8),
}));
console.log('Obj a2', (merged.validate({ foo: [1,2,3,4,5]})).error);
console.log('Obj a3', (merged.validate({ foo: [1,2,3,4,5,6,7,8]})).error);

Javascript Object: Setting a value to be equal to a previous Key

In javascript, is there anyway to set a value equal to a previous key that was declared during initialization?
for example,
const object = {
a: "test",
b: a
}
console.log(object)
or
const object = {
a: "test",
b: object.a
}
console.log(object)
How can I achieve this result in the console?
{ a: 'test', b: 'test' }
I understand that this is redundant, so let me explain what I'm trying to achieve.
I want to be able to set a url in one value, and then add to it using a previous value. The reason for this is to clean up the code and set formulas into one object.
Example
const object = {
base_url: "www.google.com",
images_url: `${base_url}/images`,
maps_url: `${base_url}/maps`
}
console.log(object)
The closest thing I can think of in Javascript is to use a getter.
const object = {
a: "test",
get b(){
return this.a+"something else";
}
}
console.log(object)
Getter/Setters will save your day
const object = {
a: "test",
get b(){return this.a}
}
console.log(object)

With JavaScript Flow, how to limit allowed values to type's keys?

What should be put in place of ??? so that the following would work:
type Product = {
id: number,
name: string;
}
const foo: ??? = 'id' // works
const bar: ??? = 'name' // works
const baz: ??? = 'someField' // FAIL!
You can use the $Keys utility type that will extract all keys from a type and produce a union of them.
type Product = {
id: number,
name: string;
}
const foo: $Keys<Product> = 'id' // works
const bar: $Keys<Product> = 'name' // works
const baz: $Keys<Product> = 'someField' // FAIL!
See a live example
In effect $Keys<Product> is the same as "id" | "name" but it's dynamically calculated based on the properties present in Product. You can also extract the type if you want to re-use it a lot:
type ValidKey = $Keys<Product>
const foo: ValidKey = "id"

Is there a way to capture a variable access? [duplicate]

Is there a way to set the default attribute of a Javascript object such that:
let emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue
Since I asked the question several years ago things have progressed nicely.
Proxies are part of ES6. The following example works in Chrome, Firefox, Safari and Edge:
let handler = {
get: function(target, name) {
return target.hasOwnProperty(name) ? target[name] : 42;
}
};
let emptyObj = {};
let p = new Proxy(emptyObj, handler);
p.answerToTheUltimateQuestionOfLife; //=> 42
Read more in Mozilla's documentation on Proxies.
Use destructuring (new in ES6)
There is great documentation by Mozila as well as a fantastic blog post that explains the syntax better than I can.
To Answer Your Question
var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue
Going Further
Can I rename this variable? Sure!
const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15
What about nested data? Bring it on!
var nestedData = {
name: 'Awesome Programmer',
languages: [
{
name: 'javascript',
proficiency: 4,
}
],
country: 'Canada',
};
var {name: realName, languages: [{name: languageName}]} = nestedData ;
console.log(realName); // Awesome Programmer
console.log(languageName); // javascript
There isn't a way to set this in Javascript - returning undefined for non-existent properties is a part of the core Javascript spec. See the discussion for this similar question. As I suggested there, one approach (though I can't really recommend it) would be to define a global getProperty function:
function getProperty(o, prop) {
if (o[prop] !== undefined) return o[prop];
else return "my default";
}
var o = {
foo: 1
};
getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"
But this would lead to a bunch of non-standard code that would be difficult for others to read, and it might have unintended consequences in areas where you'd expect or want an undefined value. Better to just check as you go:
var someVar = o.someVar || "my default";
my code is:
function(s){
s = {
top: s.top || 100, // default value or s.top
left: s.left || 300, // default value or s.left
}
alert(s.top)
}
The way I achieve this is with the object.assign function
const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties); // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties); // { "foo": "foo" };
console.log(newObj); // { "foo": "foo", "bar": "foo" }
This seems to me the most simple and readable way of doing so:
let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}
options = Object.assign({}, default_options, options)
Object.assign() reference
This sure sounds like the typical use of protoype-based objects:
// define a new type of object
var foo = function() {};
// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";
// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1); // outputs defaultValue1
I think the simplest approach is using Object.assign.
If you have this Class:
class MyHelper {
constructor(options) {
this.options = Object.assign({
name: "John",
surname: "Doe",
birthDate: "1980-08-08"
}, options);
}
}
You can use it like this:
let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"
Documentation (with polyfill):
https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Or you can try this
dict = {
'somekey': 'somevalue'
};
val = dict['anotherkey'] || 'anotherval';
Simplest of all Solutions:
dict = {'first': 1,
'second': 2,
'third': 3}
Now,
dict['last'] || 'Excluded'
will return 'Excluded', which is the default value.
If you only have an object that is a single level deep (nested object properties will not merge as expected since it directly destructures from the first level), you can use the following destructuring syntax:
const options = {
somevar: 1234,
admin: true
};
const defaults = {
test: false,
admin: false,
};
var mergedOptions = {...defaults, ...options};
Of which the output would be:
console.log(options);
// { somevar: 1234, admin: true }
console.log(mergedOptions);
// { test: false, admin: true, somevar: 1234 }
Or even formatted as a single statement (this is slightly unreadable though):
const options = {...{
// Defaults
test: false,
admin: false,
}, ...{
// Overrides
somevar: 1234,
admin: true
}};
I saw an article yesterday that mentions an Object.__noSuchMethod__ property: JavascriptTips I've not had a chance to play around with it, so I don't know about browser support, but maybe you could use that in some way?
I'm surprised nobody has mentioned ternary operator yet.
var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'
attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0
In this way, even if the value of 'c' is 0, it will still get the correct value.
var obj = {
a: 2,
b: 4
};
console.log(obj);
--> {a: 2, b: 4}
function applyDefaults(obj) {
obj.a ||= 10;
obj.b ||= 10;
obj.c ||= 10;
}
// do some magic
applyDefaults(obj);
console.log(obj);
--> {a: 2, b: 4, c: 10}
This works because
undefined || "1111111" --> "1111111"
"0000000" || "1111111" --> "0000000"
as null, undefined, NaN, 0, "" (Empty String), false itself, are all considered to be equivalent to false (falsy). Anything else is true (truthy).
Note that this is not uniformly supported across browsers and nodejs versions (confirm for yourself).
So two troublesome cases are the empty String "" and 0 (zero). If it is important not to override those, you might need to rewrite this as:
if (typeof obj.d == "undefined") obj.d = "default"
This will be better supported across browsers also.
Alternatively you could write this as:
obj.d ??= "default"
This is the nullish assignment which applies only to values that are null or undefined (nullish) - of which the empty string is not part. However, this has again a diminished cross-browser support.
See also on the official Mozilla Website - Assigning a default value to a variable.
This is actually possible to do with Object.create. It will not work for "non defined" properties. But for the ones that has been given a default value.
var defaults = {
a: 'test1',
b: 'test2'
};
Then when you create your properties object you do it with Object.create
properties = Object.create(defaults);
Now you will have two object where the first object is empty, but the prototype points to the defaults object. To test:
console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));
Object.withDefault = (defaultValue,o={}) => {
return new Proxy(o, {
get: (o, k) => (k in o) ? o[k] : defaultValue
});
}
o = Object.withDefault(42);
o.x //=> 42
o.x = 10
o.x //=> 10
o.xx //=> 42
One approach would be to take a defaults object and merge it with the target object. The target object would override values in the defaults object.
jQuery has the .extend() method that does this. jQuery is not needed however as there are vanilla JS implementations such as can be found here:
http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
With the addition of the Logical nullish assignment operator, you can now do something like this
const obj = {}
obj.a ??= "default";
In the case where you have an empty list as the default value and want to push to it, you could do
const obj = {}
(obj.a ??= []).push("some value")
I came here looking for a solution because the header matched my problem description but it isn't what i was looking for but i got a solution to my problem(I wanted to have a default value for an attribute which would be dynamic something like date).
let Blog = {
title : String,
image : String,
body : String,
created: {type: Date, default: Date.now}
}
The above code was the solution for which i finally settled.

Default property on Javascript object [duplicate]

Is there a way to set the default attribute of a Javascript object such that:
let emptyObj = {};
// do some magic
emptyObj.nonExistingAttribute // => defaultValue
Since I asked the question several years ago things have progressed nicely.
Proxies are part of ES6. The following example works in Chrome, Firefox, Safari and Edge:
let handler = {
get: function(target, name) {
return target.hasOwnProperty(name) ? target[name] : 42;
}
};
let emptyObj = {};
let p = new Proxy(emptyObj, handler);
p.answerToTheUltimateQuestionOfLife; //=> 42
Read more in Mozilla's documentation on Proxies.
Use destructuring (new in ES6)
There is great documentation by Mozila as well as a fantastic blog post that explains the syntax better than I can.
To Answer Your Question
var emptyObj = {};
const { nonExistingAttribute = defaultValue } = emptyObj;
console.log(nonExistingAttribute); // defaultValue
Going Further
Can I rename this variable? Sure!
const { nonExistingAttribute: coolerName = 15} = emptyObj;
console.log(coolerName); // 15
What about nested data? Bring it on!
var nestedData = {
name: 'Awesome Programmer',
languages: [
{
name: 'javascript',
proficiency: 4,
}
],
country: 'Canada',
};
var {name: realName, languages: [{name: languageName}]} = nestedData ;
console.log(realName); // Awesome Programmer
console.log(languageName); // javascript
There isn't a way to set this in Javascript - returning undefined for non-existent properties is a part of the core Javascript spec. See the discussion for this similar question. As I suggested there, one approach (though I can't really recommend it) would be to define a global getProperty function:
function getProperty(o, prop) {
if (o[prop] !== undefined) return o[prop];
else return "my default";
}
var o = {
foo: 1
};
getProperty(o, 'foo'); // 1
getProperty(o, 'bar'); // "my default"
But this would lead to a bunch of non-standard code that would be difficult for others to read, and it might have unintended consequences in areas where you'd expect or want an undefined value. Better to just check as you go:
var someVar = o.someVar || "my default";
my code is:
function(s){
s = {
top: s.top || 100, // default value or s.top
left: s.left || 300, // default value or s.left
}
alert(s.top)
}
The way I achieve this is with the object.assign function
const defaultProperties = { 'foo': 'bar', 'bar': 'foo' };
const overwriteProperties = { 'foo': 'foo' };
const newObj = Object.assign({}, defaultProperties, overwriteProperties);
console.log(defaultProperties); // {"foo": "bar", "bar": "foo"}
console.log(overwriteProperties); // { "foo": "foo" };
console.log(newObj); // { "foo": "foo", "bar": "foo" }
This seems to me the most simple and readable way of doing so:
let options = {name:"James"}
const default_options = {name:"John", surname:"Doe"}
options = Object.assign({}, default_options, options)
Object.assign() reference
This sure sounds like the typical use of protoype-based objects:
// define a new type of object
var foo = function() {};
// define a default attribute and value that all objects of this type will have
foo.prototype.attribute1 = "defaultValue1";
// create a new object of my type
var emptyObj = new foo();
console.log(emptyObj.attribute1); // outputs defaultValue1
I think the simplest approach is using Object.assign.
If you have this Class:
class MyHelper {
constructor(options) {
this.options = Object.assign({
name: "John",
surname: "Doe",
birthDate: "1980-08-08"
}, options);
}
}
You can use it like this:
let helper = new MyHelper({ name: "Mark" });
console.log(helper.options.surname); // this will output "Doe"
Documentation (with polyfill):
https://developer.mozilla.org/it/docs/Web/JavaScript/Reference/Global_Objects/Object/assign
Or you can try this
dict = {
'somekey': 'somevalue'
};
val = dict['anotherkey'] || 'anotherval';
Simplest of all Solutions:
dict = {'first': 1,
'second': 2,
'third': 3}
Now,
dict['last'] || 'Excluded'
will return 'Excluded', which is the default value.
If you only have an object that is a single level deep (nested object properties will not merge as expected since it directly destructures from the first level), you can use the following destructuring syntax:
const options = {
somevar: 1234,
admin: true
};
const defaults = {
test: false,
admin: false,
};
var mergedOptions = {...defaults, ...options};
Of which the output would be:
console.log(options);
// { somevar: 1234, admin: true }
console.log(mergedOptions);
// { test: false, admin: true, somevar: 1234 }
Or even formatted as a single statement (this is slightly unreadable though):
const options = {...{
// Defaults
test: false,
admin: false,
}, ...{
// Overrides
somevar: 1234,
admin: true
}};
I saw an article yesterday that mentions an Object.__noSuchMethod__ property: JavascriptTips I've not had a chance to play around with it, so I don't know about browser support, but maybe you could use that in some way?
I'm surprised nobody has mentioned ternary operator yet.
var emptyObj = {a:'123', b:'234', c:0};
var defaultValue = 'defaultValue';
var attr = 'someNonExistAttribute';
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue;//=> 'defaultValue'
attr = 'c'; // => 'c'
emptyObj.hasOwnProperty(attr) ? emptyObj[attr] : defaultValue; // => 0
In this way, even if the value of 'c' is 0, it will still get the correct value.
var obj = {
a: 2,
b: 4
};
console.log(obj);
--> {a: 2, b: 4}
function applyDefaults(obj) {
obj.a ||= 10;
obj.b ||= 10;
obj.c ||= 10;
}
// do some magic
applyDefaults(obj);
console.log(obj);
--> {a: 2, b: 4, c: 10}
This works because
undefined || "1111111" --> "1111111"
"0000000" || "1111111" --> "0000000"
as null, undefined, NaN, 0, "" (Empty String), false itself, are all considered to be equivalent to false (falsy). Anything else is true (truthy).
Note that this is not uniformly supported across browsers and nodejs versions (confirm for yourself).
So two troublesome cases are the empty String "" and 0 (zero). If it is important not to override those, you might need to rewrite this as:
if (typeof obj.d == "undefined") obj.d = "default"
This will be better supported across browsers also.
Alternatively you could write this as:
obj.d ??= "default"
This is the nullish assignment which applies only to values that are null or undefined (nullish) - of which the empty string is not part. However, this has again a diminished cross-browser support.
See also on the official Mozilla Website - Assigning a default value to a variable.
This is actually possible to do with Object.create. It will not work for "non defined" properties. But for the ones that has been given a default value.
var defaults = {
a: 'test1',
b: 'test2'
};
Then when you create your properties object you do it with Object.create
properties = Object.create(defaults);
Now you will have two object where the first object is empty, but the prototype points to the defaults object. To test:
console.log('Unchanged', properties);
properties.a = 'updated';
console.log('Updated', properties);
console.log('Defaults', Object.getPrototypeOf(properties));
Object.withDefault = (defaultValue,o={}) => {
return new Proxy(o, {
get: (o, k) => (k in o) ? o[k] : defaultValue
});
}
o = Object.withDefault(42);
o.x //=> 42
o.x = 10
o.x //=> 10
o.xx //=> 42
One approach would be to take a defaults object and merge it with the target object. The target object would override values in the defaults object.
jQuery has the .extend() method that does this. jQuery is not needed however as there are vanilla JS implementations such as can be found here:
http://gomakethings.com/vanilla-javascript-version-of-jquery-extend/
With the addition of the Logical nullish assignment operator, you can now do something like this
const obj = {}
obj.a ??= "default";
In the case where you have an empty list as the default value and want to push to it, you could do
const obj = {}
(obj.a ??= []).push("some value")
I came here looking for a solution because the header matched my problem description but it isn't what i was looking for but i got a solution to my problem(I wanted to have a default value for an attribute which would be dynamic something like date).
let Blog = {
title : String,
image : String,
body : String,
created: {type: Date, default: Date.now}
}
The above code was the solution for which i finally settled.

Categories

Resources