Destructing object in JS [duplicate] - javascript

Let's suppose I have the following object:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
And that I want only the id and fullName.
I will do the following :
const { id, fullName } = user
Easy-peasy, right?
Now let's suppose that I want to do the destructuring based on the value of another variable called fields.
const fields = [ 'id', 'fullName' ]
Now my question is : How can I do destructuring based on an array of keys?
I shamelessly tried the following without success:
let {[{...fields}]} = user and let {[...fields]} = user. Is there any way that this could be done?
Thank you

It's not impossible to destructure with a dynamic key. To prevent the problem of creating dynamic variables (as Ginden mentioned) you need to provide aliases.
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
const {[fields[0]]: id, [fields[1]]: fullName} = user;
console.log(id); // 42
console.log(fullName); // { firstName: "John", lastName: "Doe" }
To get around the problem of having to define static aliases for dynamic values, you can assign to an object's dynamic properties. In this simple example, this is the same as reverting the whole destructuring, though :)
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
({[fields[0]]: object[fields[0]], [fields[1]]: object[fields[1]]} = user);
console.log(object.id); // 42
console.log(object.fullName); // { firstName: "John", lastName: "Doe" }
sources:
https://twitter.com/ydkjs/status/699845396084846592
https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md#not-just-declarations

Paul Kögel's answer is great, but I wanted to give a simpler example for when you need only the value of a dynamic field but don't need to assign it to a dynamic key.
let obj = {x: 3, y: 6};
let dynamicField = 'x';
let {[dynamicField]: value} = obj;
console.log(value);

Short answer: it's impossible and it won't be possible.
Reasoning behind this: it would introduce new dynamically named variables into block scope, effectively being dynamic eval, thus disabling any performance optimization. Dynamic eval that can modify scope in fly was always regarded as extremely dangerous and was removed from ES5 strict mode.
Moreover, it would be a code smell - referencing undefined variables throws ReferenceError, so you would need more boilerplate code to safely handle such dynamic scope.

As discussed before, you can't destruct into dynamically named variables in JavaScript without using eval.
But you can get a subset of the object dynamically, using reduce function as follows:
const destruct = (obj, ...keys) =>
keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const object = {
color: 'red',
size: 'big',
amount: 10,
};
const subset1 = destruct(object, 'color');
const subset2 = destruct(object, 'color', 'amount', 'size');
console.log(subset1);
console.log(subset2);

You can't destruct without knowing the name of the keys or using an alias for named variables
// you know the name of the keys
const { id, fullName } = user;
// use an alias for named variables
const { [fields[0]]: id, [fields[1]]: fullName } = user;
A solution is to use Array.reduce() to create an object with the dynamic keys like this:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName', 'age' ];
const obj = fields.reduce((acc, k) => ({ ...acc, ...(user.hasOwnProperty(k) && { [k]: user[k] }) }), {});
for(let k in obj) {
console.log(k, obj[k]);
}

I believe that the above answers are intellectual and valid because all are given by pro developers. :). But, I have found a small and effective solution to destructure any objects dynamically. you can destructure them in two ways. But both ways are has done the same action.
Ex:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
using "Object.key", "forEach" and "window" object.
Object.keys(user).forEach(l=>window[l]=user[l]);
Simply using Object. assign method.
Object.assign(window, user)
Output:
console.log(id, displayName, fullName)
// 42 jdoe {firstName: "John", lastName: "Doe"}
Anyway, I am a newbie in JS. So, don't take it as an offense if you found any misleading info in my answer.

Related

How to pass an object and only change one value?

I have a data object below.
{
name: "Catherine Myer",
age: 23,
birthday: "august"
}
If in need to pass the data as a prop to a component, BUT would also like to change just the age to: 24. How do i do so?
<NextPage data={author.age = 24}/>
I need the final object to be:
{
name: "Catherine Myer",
age: 24,
birthday: "august"
}
You can do it with spread syntax:
<NextPage data={{...author, age: 24}}/>
Either pass individual prop values by spreading author (see Spread Attributes) and override age with a separate prop, eg
const NextPage = ({ name, age, birthday }) => {
// ...
};
<NextPage {...author} age="24" />
or extend the existing object and provide a new age property
const NextPage = ({ data: { name, age, birthday } }) => {
// ...
};
<NextPage data={{...author, age: 24}} />
You can just use the JS spread syntax to update whichever properties you need.
const author = {
name: "Catherine Myer",
age: 23,
birthday: "august"
};
const data = {
age: 24
};
const updatedAuthor = { ...author, ...data };
Edit: I have no idea what I was thinking to make it this complicated...
If you don't know which property will be overwritten, a simple for in loop can make the update. As a bonus, this scales up if you want to modify the value of more than one property at once.
Alternatively, if you really want to (or if you make the change Mike Kamermans recommended), you can use the JS spread syntax to achieve the same.
const author = {
name: "Catherine Myer",
age: 23,
birthday: "august"
};
const data = {
age: 24
};
// OPTION 1: for in loop
let updatedAuthor = { ...author }; // optionally create a copy to avoid mutating the original object
for(let prop in data) {
updatedAuthor[prop] = data[prop];
}
// OPTION 2: spread syntax
const propToUpdate = Object.keys(update)?.[0];
const updatedAuthor = {
...author,
[propToUpdate]: update[propToUpdate]
}

Shorthand for picking object properties - combine ES6 `Object Deconstruction` with `Object Property Value` shorthand

Following code outputs {name: "Bob", surname: "Smith"} and it works fine. I want to know can I make it shorter.
((person = { name: 'Bob', surname: 'Smith', age: 22, }) => {
const {
name, // (a) create variable from deconstructing
surname,
} = person;
return {
name, // (b) reuse variable as new object parameter name (and value)
surname
}
})();
Can I somehow merge object deconstruction to variables (a) with returning a new object with Object Property Value shorthand (b)?
I use here shorthand but then its purpose is defeated by the need to manually re-use parameters. I want to mention the name or surname word in my function once not twice...
Destructure person in the function's declaration:
const result = (({ name, surname } = { name: 'Bob', surname: 'Smith', age: 22, }) => ({
name, // (b) reuse variable as new object parameter name (and value)
surname
}))();
console.log(result);
You can not mention it at all
((person = { name: 'Bob', surname: 'Smith', age: 22, }) => {
const {age,...ans} = person;
return ans
})()

How can you define an objects properties as variables without knowing their names? [duplicate]

Let's suppose I have the following object:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
And that I want only the id and fullName.
I will do the following :
const { id, fullName } = user
Easy-peasy, right?
Now let's suppose that I want to do the destructuring based on the value of another variable called fields.
const fields = [ 'id', 'fullName' ]
Now my question is : How can I do destructuring based on an array of keys?
I shamelessly tried the following without success:
let {[{...fields}]} = user and let {[...fields]} = user. Is there any way that this could be done?
Thank you
It's not impossible to destructure with a dynamic key. To prevent the problem of creating dynamic variables (as Ginden mentioned) you need to provide aliases.
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
const {[fields[0]]: id, [fields[1]]: fullName} = user;
console.log(id); // 42
console.log(fullName); // { firstName: "John", lastName: "Doe" }
To get around the problem of having to define static aliases for dynamic values, you can assign to an object's dynamic properties. In this simple example, this is the same as reverting the whole destructuring, though :)
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
({[fields[0]]: object[fields[0]], [fields[1]]: object[fields[1]]} = user);
console.log(object.id); // 42
console.log(object.fullName); // { firstName: "John", lastName: "Doe" }
sources:
https://twitter.com/ydkjs/status/699845396084846592
https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md#not-just-declarations
Paul Kögel's answer is great, but I wanted to give a simpler example for when you need only the value of a dynamic field but don't need to assign it to a dynamic key.
let obj = {x: 3, y: 6};
let dynamicField = 'x';
let {[dynamicField]: value} = obj;
console.log(value);
Short answer: it's impossible and it won't be possible.
Reasoning behind this: it would introduce new dynamically named variables into block scope, effectively being dynamic eval, thus disabling any performance optimization. Dynamic eval that can modify scope in fly was always regarded as extremely dangerous and was removed from ES5 strict mode.
Moreover, it would be a code smell - referencing undefined variables throws ReferenceError, so you would need more boilerplate code to safely handle such dynamic scope.
As discussed before, you can't destruct into dynamically named variables in JavaScript without using eval.
But you can get a subset of the object dynamically, using reduce function as follows:
const destruct = (obj, ...keys) =>
keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const object = {
color: 'red',
size: 'big',
amount: 10,
};
const subset1 = destruct(object, 'color');
const subset2 = destruct(object, 'color', 'amount', 'size');
console.log(subset1);
console.log(subset2);
You can't destruct without knowing the name of the keys or using an alias for named variables
// you know the name of the keys
const { id, fullName } = user;
// use an alias for named variables
const { [fields[0]]: id, [fields[1]]: fullName } = user;
A solution is to use Array.reduce() to create an object with the dynamic keys like this:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName', 'age' ];
const obj = fields.reduce((acc, k) => ({ ...acc, ...(user.hasOwnProperty(k) && { [k]: user[k] }) }), {});
for(let k in obj) {
console.log(k, obj[k]);
}
I believe that the above answers are intellectual and valid because all are given by pro developers. :). But, I have found a small and effective solution to destructure any objects dynamically. you can destructure them in two ways. But both ways are has done the same action.
Ex:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
using "Object.key", "forEach" and "window" object.
Object.keys(user).forEach(l=>window[l]=user[l]);
Simply using Object. assign method.
Object.assign(window, user)
Output:
console.log(id, displayName, fullName)
// 42 jdoe {firstName: "John", lastName: "Doe"}
Anyway, I am a newbie in JS. So, don't take it as an offense if you found any misleading info in my answer.

what is the most terse way to return an array of entities in typescript?

I'm trying to figure out the most terse way to return an array of objects from a ts function. The following function works as expected:
getAuthors1(): Author[]
{
var authors: Author[] =
[
{
FirstName: "John";
MI: "J";
LastName: "Smith";
}
];
return authors;
}
The following function errors out b/c it appears that ts won't let me return an object array directly as opposed to as a variable:
getAuthors2(): Author[]
{
return Author[] =
[
{
FirstName: "John";
MI: "J";
LastName: "Smith";
}
];
}
The following function errors out b/c a value isn't provided for MI:
getAuthors3(): Author[]
{
var authors: Author[] =
[
{
FirstName: "John";
LastName: "Smith";
}
];
return authors;
}
Questions:
Are values required for all object properties when creating an object initialized array?
1a. If this is the case do developers typically initialize property values in the class?
Is there a way to return an object array directly, similar to my getAuthors2() example above, as opposed to having to assign this to a variable and then return the variable?
If you have an interface defined and you create an object where you tell TypeScript that it should be of that type, it will complain for any missing property, as it should.
One way to get around this is to use a mapped type where you state that each property of the object is optional, and use it like Partial< Author >. See the official documentation for more info.
You can return the array right away, just remove the type that you've added after return:
getAuthors2(): Author[] {
return [
{
FirstName: 'John',
MI: 'J',
LastName: 'Smith',
}
];
}
Also wherever possible you should remove the manually defined types, like the return Author[] from your functions. TypeScript will use type inference to figure it out by itself.
In your specific example either you leave the return type defined, and typescript will make the required checks or use something similar to what you have in getAuthors3. If you get or have the objects already typed just place them in the array and TypeScript will do the rest:
getAuthors() {
const author: Author = {
FirstName: 'John',
MI: 'J',
LastName: 'Smith',
};
return [author];
}
Return the array, not the result of an array assignment.
function getAuthors() {
return [{
FirstName: "John",
MI: "J",
LastName: "Smith"
}];
}
console.log(getAuthors());

How to destructure into dynamically named variables in ES6?

Let's suppose I have the following object:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
And that I want only the id and fullName.
I will do the following :
const { id, fullName } = user
Easy-peasy, right?
Now let's suppose that I want to do the destructuring based on the value of another variable called fields.
const fields = [ 'id', 'fullName' ]
Now my question is : How can I do destructuring based on an array of keys?
I shamelessly tried the following without success:
let {[{...fields}]} = user and let {[...fields]} = user. Is there any way that this could be done?
Thank you
It's not impossible to destructure with a dynamic key. To prevent the problem of creating dynamic variables (as Ginden mentioned) you need to provide aliases.
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
const {[fields[0]]: id, [fields[1]]: fullName} = user;
console.log(id); // 42
console.log(fullName); // { firstName: "John", lastName: "Doe" }
To get around the problem of having to define static aliases for dynamic values, you can assign to an object's dynamic properties. In this simple example, this is the same as reverting the whole destructuring, though :)
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName' ];
const object = {};
({[fields[0]]: object[fields[0]], [fields[1]]: object[fields[1]]} = user);
console.log(object.id); // 42
console.log(object.fullName); // { firstName: "John", lastName: "Doe" }
sources:
https://twitter.com/ydkjs/status/699845396084846592
https://github.com/getify/You-Dont-Know-JS/blob/master/es6%20%26%20beyond/ch2.md#not-just-declarations
Paul Kögel's answer is great, but I wanted to give a simpler example for when you need only the value of a dynamic field but don't need to assign it to a dynamic key.
let obj = {x: 3, y: 6};
let dynamicField = 'x';
let {[dynamicField]: value} = obj;
console.log(value);
Short answer: it's impossible and it won't be possible.
Reasoning behind this: it would introduce new dynamically named variables into block scope, effectively being dynamic eval, thus disabling any performance optimization. Dynamic eval that can modify scope in fly was always regarded as extremely dangerous and was removed from ES5 strict mode.
Moreover, it would be a code smell - referencing undefined variables throws ReferenceError, so you would need more boilerplate code to safely handle such dynamic scope.
As discussed before, you can't destruct into dynamically named variables in JavaScript without using eval.
But you can get a subset of the object dynamically, using reduce function as follows:
const destruct = (obj, ...keys) =>
keys.reduce((a, c) => ({ ...a, [c]: obj[c] }), {});
const object = {
color: 'red',
size: 'big',
amount: 10,
};
const subset1 = destruct(object, 'color');
const subset2 = destruct(object, 'color', 'amount', 'size');
console.log(subset1);
console.log(subset2);
You can't destruct without knowing the name of the keys or using an alias for named variables
// you know the name of the keys
const { id, fullName } = user;
// use an alias for named variables
const { [fields[0]]: id, [fields[1]]: fullName } = user;
A solution is to use Array.reduce() to create an object with the dynamic keys like this:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
const fields = [ 'id', 'fullName', 'age' ];
const obj = fields.reduce((acc, k) => ({ ...acc, ...(user.hasOwnProperty(k) && { [k]: user[k] }) }), {});
for(let k in obj) {
console.log(k, obj[k]);
}
I believe that the above answers are intellectual and valid because all are given by pro developers. :). But, I have found a small and effective solution to destructure any objects dynamically. you can destructure them in two ways. But both ways are has done the same action.
Ex:
const user = {
id: 42,
displayName: "jdoe",
fullName: {
firstName: "John",
lastName: "Doe"
}
};
using "Object.key", "forEach" and "window" object.
Object.keys(user).forEach(l=>window[l]=user[l]);
Simply using Object. assign method.
Object.assign(window, user)
Output:
console.log(id, displayName, fullName)
// 42 jdoe {firstName: "John", lastName: "Doe"}
Anyway, I am a newbie in JS. So, don't take it as an offense if you found any misleading info in my answer.

Categories