Array of objects which have all the same properties - javascript

I was wondering, if it's possible to ensure with Angular 12 / Typescript, that all objects within an array have the same properties, without declaring the properties explicitly (should be generic).
Here's an example of what I want to achieve:
// This should compile because all objects have the same properties
const correct = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
]
// This shouldn't compile because some object have different properties
const wrong = [
{firstname: 'Aline', lastname: 'Rose', phone: 'xxx-xxx-xx-xx'},
{firstname: 'Daniel', email: 'dan#gmail.com'},
{firstname: 'Louisa', email: 'louisa#icloud.com'}
]
I was able to create an Interface which only allows properties with type string, but I couldn't achieve the example above.
export interface Data {
[keys: string]: string
}
Update (Use-Case)
I need this check in a service which exports data. You should be able to pass an array of objects, which represent rows within a table.
For example:
const data = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
]
this.exportService.export(data);
This code would generate a file with a table like this:
firstname
lastname
Jack
Sanders
Susanna
Marsaglia
The service should support any passed data, because it's used widely over our entire application. But to be sure that the service can export the data to a table, we need to ensure, that all passed objects have the same properties (e.g. columns).

function sameKeys(input) {
if (!input || input.length === 0) return;
const keys = new Set(Object.keys(input[0]));
return input.every((item) => Object.keys(item).every((key) => keys.has(key)));
}
If you want a compile time check, then doing a proper type definition makes sense have given in another answer. But that will only work if this data is hardcoded. if you are fetching it from backend it will not work as types are lost when the code is already build as javascript don't have types.

You can very well make your exportservice generic, ie something like this
class ExportService {
public export<T>(data: T[]) {
console.log(data);
}
}
Or you can also just use {[key:string]:string} as element type in you export service
class ExportService {
public export(data: {[key:string]:string}[]) {
console.log(data);
}
}
That doesn't hinder you from defining the type of your data correctly.
const data: { firstname: string, lastname: string}[] = [
{ firstname: "john", lastname: "foo"},
{ firstname: "jim", lastname: "bar"}
];
this.exportservice.export(data);
See also this fiddle

const data = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
]
const dataReference : Required<typeof data[number]>[] = data

You should achieve this by interface as below
interface IStructure {
firstname: string;
lastname: string;
}
const correct: Array<IStructure> = [
{firstname: 'Jack', lastname: 'Sanders'},
{firstname: 'Susanna', lastname: 'Marsaglia'},
{firstname: 'Walter', lastname: 'Walker'}
];
//wrong will throw error

Related

Why getting "Destructuring expressions can only have identifier references" when trying to destruct an object?

I have the following object:
const john = {
family: [
{ firstName: 'david', secondName: 'jana' },
{ firstName: 'eyal', secondName: 'shani ' },
],
};
I want to get 'david' string in one operation. So i tried the following code:
const { family:[0]{firstName}}} = john;
But i'm getting the error :
"Destructuring expressions can only have identifier references"
Can someone tell me in simple words (cause i'm new in the language) what i'm doing wrong?
To extract a deeply nested value with destructuring, the syntax is nearly identical to when declaring an object with those properties. family:[0] isn't valid syntax - instead, you need to surround the contents of family in array delimiters:
const john = {
family: [{
firstName: 'david',
secondName: 'jana'
},
{
firstName: 'eyal',
secondName: 'shani '
},
],
};
const { family:[{firstName}]} = john;
console.log(firstName);
But I'd highly recommend against using nested destructuring like this. It's so hard to write and read and understand. Better to use plain dot notation at least for the outer accesses, eg
const john = {
family: [{
firstName: 'david',
secondName: 'jana'
},
{
firstName: 'eyal',
secondName: 'shani '
},
],
};
const { firstName } = john.family[0];
console.log(firstName);

How do you add multiple objects to an array? (JavaScript)

I'm not sure if I phrased the question right. I'm fairly new to JavaScript, and I'd like to add multiple objects (?) to an array.
If I have this array:
let arr = [{
firstname: "John",
lastname: "Smith"
}];
How would I add, say
var firstname = "John";
var lastname = "Doe";
as
{ firstname: "John", lastname: "Doe" }
to the same array?
Items can be added to an array with the push method. Every array has this method build it, together with many other methods, and can be used to push a new value to the end of the array.
var arr = [
{
firstname: "John",
lastname: "Smith"
}
];
In the push method create an object with the keys and the values that you want to add.
var firstname = "John";
var lastname = "Doe";
arr.push({
firsName: firstName,
lastName: lastName
});
If the keys of the object are the same name as the variables then you can use the syntax below. This will give the object keys with the same name as the variable and set the value of the variable with it as the value of the key.
arr.push({ firstName, lastName });
Alternatively if you want to add an object to the beginning of the array, use the unshift method of the array.
arr.unshift({ firstName, lastName });
You can also do this with spread operator:
var arr = [{firstname: "John", lastname: "Smith"}];
arr= [...arr, {firstname: "Name1", lastname: "LName"}]
console.log(arr);
Take a look at push.
let arr = [{
firstname: "John",
lastname: "Smith"
}];
var firstname = "soham";
var lastname = "s";
arr.push({
firstname: firstname,
lastname: lastname
})
console.log(arr);

Advanced Destructuring of objects in ES6

I have the following object:
personObj = {
_id : '123',
first_name: 'John',
last_name: 'Doe',
}
I would like to destructure it to the following variables:
id, <-- _id
name: {
first, <-- first_name
last <-- last_name
}
(I want first_name and last_name to reside inside a 'name' object)
I've tried the following syntax:
const {
id: _id,
name: {
first: first_name,
last: last_name
}
} = personObj
However this causes an error.
What am I doing wrong?
Update
Chapter 10. Destructuring of book "Exploring ES 6" provides many advanced examples of how to use destructuring and explains how it works internally.
Destructuring can extract values directly into the properties of an object. The properties are not required to exist but all destination objects must already exist when the destructuring assignment happens.
Armed with this knowledge, the code that answers the question is:
let personObj = {
_id: '123',
first_name: 'John',
last_name: 'Doe',
}
// Create the objects that receive the values on destructuring
let c = { name: {} }
// Do the magic
({ _id: c.id, first_name: c.name.first, last_name: c.name.last } = personObj)
console.log(c)
// {id: "123", name: {first: "John", last: "Doe"}}
The parentheses around the assignment expression that uses destructuring are required, without them the engine reports a syntax error at the first :.
The original answer follows. It doesn't completely answer the question but I leave it here for reference. It shows how to use the rest properties (...) in destructuring expressions and it was accepted by the OP, as incomplete as it is.
The original answer
Destructuring with properties renaming works the other way around: the original name is placed before the colon, the new name is after it.
let personObj = {
_id: '123',
first_name: 'John',
last_name: 'Doe',
}
// Destructure personObj using different names for the properties
const {
_id: id,
first_name: first,
last_name: last
} = personObj
console.log('id: ' + id);
console.log('first: ' + first);
console.log('last: ' + last);
// Output
// id: 123
// first: John
// last: Doe
You can then assemble the pieces (id, first, last) into a new object:
let c = {
id,
name: {
first,
last
}
}
console.log(c);
// Output
// { id: '123', name: { first: 'John', last: 'Doe' } }
Update
The most similar result to what you describe in the question can be achieved by:
let { _id: id, ...name } = personObj
console.log(id)
console.log(name)
// Output
// 123
// { first_name: 'John', last_name: 'Doe' }
But this way the properties of name use the same names they have in personObj. Even more, it doesn't work any more if you add to personObj properties after last_name that you don't want to copy in name.

How to call for object keys in javascript (codecademy)

I'm following an online course in Javascript from Codecademy but i'm stuck in an assignment.
I'm trying to list the firstName key from my "friends list".
I have to do this with a "for in" statement in a function.
The firstName key is within the object "Steve", which in in an object "Friends".
This is the code that i have at the moment:
var friends = {
steve: {
firstName: 'Steve',
lastName: 'Jobs',
number: '1',
address: ['Fregataan','65','8546','RG','Amsterdam','The Netherlands'],
},
bill: {
firstName: 'Bill',
lastName: 'Gates',
number: '2',
address: ['Fregataan','665','8546','RG','Amsterdam','The Netherlands'],
},
};
function list(friends){
for (var firstName in friends){
console.log(friends.keys(firstName))
}
}
list(friends.keys);
This is the assignment I get from the course:
1. Create a function list that takes a single parameter.
2. In the body of the function, write a for/in loop.
3. In the loop, use console.log to print out the key. (For example, if you only have bill and steve as entries, list should just print out "bill" and "steve".)
The object "friends" was already written in a previous assignment. The function has to be written in this assignment. Can someone please find my mistake and tell me what i did wrong?
Greetings,
Luuk
I think it might be a tricky question. You are trying to print the firstName key which (if done correctly) will print out "Steve" and "Bill", but the assignment, as you described it, is to print out the key (i.e. "steve" and "bill"). So if that's the case, you should just print out the key:
function list(friends){
for (var key in friends){
console.log(key);
}
}
Hope this helps.
You should play around with it a bit more.
No need to use 'keys'.
var friends = {
steve: {
firstName: 'Steve',
lastName: 'Jobs',
number: '1',
address: ['Fregataan','65','8546','RG','Amsterdam','The Netherlands'],
},
bill: {
firstName: 'Bill',
lastName: 'Gates',
number: '2',
address: ['Fregataan','665','8546','RG','Amsterdam','The Netherlands'],
},
};
function list(friends){
console.log(friends);
for (var friend in friends){
console.log(friend);
var f = friends[friend];
console.log(f.firstName);
}
}
list(friends);

how to check true condition in iCanHaz (Moustache Template engine)

I've this json return
data = [
{ firstName: "Christophe",
lastName: "Coenraets"},
{ firstName: "John",
lastName: "Smith"}
];
I want to display each object in a li list and want to use Enumerable condition. I understand if it'd been like
data = { elem :[
{ firstName: "Christophe",
lastName: "Coenraets"},
{ firstName: "John",
lastName: "Smith"}
]};
I can use something like
{{#elem}}
<li>{{firstName}} {{lastName}}</li>
{{/elem}}
But in the first case, how do I check the condition?
I don't work with icanhaz, it very well may have a method to parse the data that you get, but you could always modify the JSON object and wrap it into a parent element like in your second case:
myData = { elem : data};

Categories