I have an object for validation that might look like this:
const exampleObject = {
foo: {
entries: {
'785bac64-c6ce-4878-bfb8-9cf5b32e2438': {
name: 'First object',
},
'117450da-315b-4676-ad23-edd94a4b6b51': {
name: 'Second object',
},
},
},
}
The keys of the entries object are dynamic (uuids). I want to validate that the name property in any of those objects is not an empty string. However, entries is not required, it is only required that if there are any entries, they cannot contain an empty string. How can I do this with Yup?
const exampleObjectValidation = Yup.object().shape({
foo: Yup.object({
entries: Yup.object({
/* what goes here ? */
})
})
})
Here's how I did it:
const exampleObjectValidation = Yup.object()
.shape({
foo: Yup.object({
entries: Yup.lazy((value) => {
if (!isEmpty(value)) {
const validationObject = { name: Yup.string().required('Item cannot be empty') }
const newEntries = Object.keys(value).reduce(
(acc, val) => ({
...acc,
[val]: Yup.object(validationObject),
}),
{}
)
return Yup.object().shape(newEntries)
}
return Yup.mixed().notRequired()
}),
}),
})
.nullable()
.notRequired()
Related
I have a Type described in typescript like this -
export type User = {
name: string;
username: string;
phoneNumber: string;
personalEmail?: string;
workEmail?: string
}
I'm fetching some data from a json file which consists of objects like these and shaping the data to this type User for each object with this function
const shaper = (obj: any): User {
const user: User = {
name: obj.name,
username: obj.username,
number: obj.number,
personalEmail: obj.personalEmail,
workEmail: obj.workEmail,
}
// remove from user the fields which have value === undefined
return user;
}
In the shaper function, I want to remove the fields of the variable user which have the value as undefined (eg : obj.personalEmail does not exist)
How do I achieve this?
Here you have a working example.
You can use delete obj[key]
const shaper = (obj) => {
const user = {
name: obj.name,
username: obj.username,
number: obj.number,
personalEmail: obj.personalEmail,
workEmail: obj.workEmail,
}
Object.entries(user).forEach(([key, value]) => {
if (value === undefined) {
delete user[key];
console.log("deleted", key);
}
});
return user;
}
const shapedResult = shaper({
name: "foo",
workEmail: "bar#bar.com"
});
console.log(shapedResult);
You could do something like this:
/* Test Data */
const test = {
name: 'name',
username: 'username',
needToRename: '123456789',
another: 'blah',
something: 'else',
workEmail: 'hello#example.com'
}
/* Example 1 */
const shaper = ({name, username, needToRename:phoneNumber, personalEmail, workEmail}) => {
return {
name,
username,
phoneNumber,
...( personalEmail !== undefined && {personalEmail} ),
...( workEmail !== undefined && {workEmail})
}
}
console.log(shaper(test));
Or you could extract the undefined check into a helper function and do this:
/* Test Data */
const test = {
name: 'name',
username: 'username',
needToRename: '123456789',
another: 'blah',
something: 'else',
workEmail: 'hello#example.com'
}
/* Example 2 */
function undefinedHelper(name, obj) {
return obj[name] === undefined ? {} : {[name]: obj[name]};
}
const shaper2 = (obj) => {
return {
name: obj.name,
username: obj.username,
phoneNumber: obj.needToRename,
...undefinedHelper('personalEmail', obj),
...undefinedHelper('workEmail', obj)
}
}
console.log(shaper2(test));
This answer was helpful: https://stackoverflow.com/a/40560953/2344607
I'm using Typescript and have this, I'm trying to create Joi validation object.
Example input :
{
key: 'name',
validate: Joi.required().options({
language: {
any: {
required: 'is required'
},
string: {
min: 'must be at least 3 Characters'
},
},
}),
}
And a method :
getObjects(inputs: Array<Input>) {
const newObject = {};
inputs.forEach(input => {
newObject[input.key] = input.validate;
});
return newObject;
}
But when checking newObject, it's only keys, and validation is undefined.
I realise this has something to do with the loop because this works.
newObject[inputs[0].key] = inputs[0].validate;
newObject[inputs[1].key] = inputs[1].validate;
I have an array of objects like this:
const data = [{
_id:"49847444033",
name:"yoko"
},{
_id:"49847433333",
name:"doira"
}]
I have to change each item name property to something like this :
...
{
_id:"49847433333",
name:{
en:"John"
}
}
My attempt is to loop object like following :
data.forEach((item) => {
item.name = {en:"john"}
console.log(item)
})
But this always console the original item and the name property value is not modified.
const newData = data.map(user => ({ _id: user._id, name: { en: user.name } }))
I created a library to express transformations like this very simply.
const { pipe, fork, get } = require('rubico')
const data =
[ { _id: '49847444033', name: 'yoko'}
, { _id: '49847433333', name: 'doira'}
]
const onData = pipe([
fork({
_id: get('_id'), // data => data._id
name: fork({ en: get('name') }), // data => ({ en: data.name })
}),
console.log,
])
data.map(onData) /*
{ _id: '49847444033', name: { en: 'yoko' } }
{ _id: '49847433333', name: { en: 'doira' } }
*/
I've commented the code above, but to really understand rubico and get started using it, I recommend you read the intuition and then the docs
try somthing like:
const newList = data.map(obj => {
return { _id: obj._id, name: { en: obj.name } }
});
and the newList list is your new data list so you can do it:
data = newList;
EDIT:
if you have more properties you can change the return line to:
return { ...obj, name: { en: obj.name } }
what will happen here, it will deploy all the object properties as they are, and modify the name property, unfortunately, every property you want to modify, you have to re-write it.
I'm trying to correctly type a function that uses Flow generic (or polymorphic) types to paginate an array of objects into a graphql/Relay-style "page" object.
Here's a simplified example:
type DBNode = {
uid: string
}
type Student = DBNode & {
username: string
}
const students = [{
uid: '123',
username: 'user-one',
}, {
uid: '345',
username: 'user-two',
}]
type Classroom = DBNode & {
room: number
}
const classrooms = [{
uid: '234',
room: 666,
}, {
uid: '456',
room: 667,
}]
type Edge<T> = {
cursor: string,
node: T
}
const itemToEdge = <T>(item: T): Edge<T> => ({
cursor: item.uid,
node: item
})
type Page<T> = {
pageInfo: {
count: number,
},
edges: Array<Edge<T>>
}
const assemblePage = <T>(items: Array<T>): Page<T> => ({
pageInfo: {
count: items.length,
},
edges: items.map(itemToEdge)
})
const studentPage = (): Page<Student> => {
return assemblePage(students)
}
const classroomPage = (): Page<Classroom> => {
return assemblePage(classrooms)
}
The error I receive is:
cursor: item.uid,
^ Cannot get `item.uid` because property `uid` is missing in `T` [1].
References:
34: const itemToEdge = <T>(item: T): Edge<T> => ({
^ [1]
Is there a to ensure that the polymorphic type T is always an object that has a uid field?
Alternatively, I tried typing assemblePage and itemToEdge to require that the item(s) are of a DBNode type, which results in:
38: node: item ^ Cannot return object literal because `DBNode` [1] is incompatible with `T` [2] in property `node`.
References:
35: const itemToEdge = <T>(item: DBNode): Edge<T> => ({
^ [1]
31: node: T ^ [2]
Demo
Edit: Here's a working version of the demo, thanks #Aleksey L for the help!
Working Demo
You can define constraint to generic type parameter:
const itemToEdge = <T: DBNode>(item: T): Edge<T> => ({
cursor: item.uid,
node: item
})
const assemblePage = <T: DBNode>(items: Array<T>): Page<T> => ({
...
})
From docs:
Generics allow you to hold onto the more specific type while adding a constraint
I want to know how to check if "novalue" exist
For example:
{
name: "maria",
city_id: "novalue"
....
}
How i do this in Vue?
Do it in <div v-if="condition"> or function?
In case you want to/can use ES7 features:
const containsKey = (obj, key ) => Object.keys(obj).includes(key);
Implementation example:
const someCoolObject = {name: 'Foo', lastName: 'Bar'};
const hasName = containsKey(someCoolObject, 'name');
const hasNickName = containsKey(someCoolObject, 'hasNickName');
console.log(hasName, hasNickName); // true, false
For Vue:
Component:
{
methods: {
containsKey(obj, key ) {
return Object.keys(obj).includes(key);
}
},
computed: {
hasName() {
return this.containsKey(this.someObject, 'name');
}
}
}
Template:
<div v-if="hasName"></div>