How to construct instance of class using json object array - javascript

I'm trying construct the class's object from the array.
import searchData from '../somepath/data.json';
And the data.json file have the following data.
[
{
"name": "London"
},
{
"name": "Paris",
}
]
Then I'm looping it using the forEach.
searchData.forEach((obj: OneClass) => {
});
Here is the class
export class OneClass{
readonly name: string;
}
It is not working well, I'm getting some kind of type error.
But when I just change the type of searchData to any then it works perfectly,
const searchData: any = [
{
'name': 'a'
},
{
'name': 'b'
},
];
Note: some code are missing due to privacy restriction, so just trying to understand how the construct the object of typescript class using array objects.
Edited:
The json data was importing using the following method.
import searchData from '../somepath/data.json';

You can either annotate your array explicitly ..
// tell TS that the variable holds an array of objects
// shaped like instances of OneClass
const searchData: OneClass[] = [
{
name: 'a'
},
{
name: 'b'
},
];
or use a so-called const assertion.
const myConstArr = [
{
name: 'bar'
} as const
// the `as const` tells TS that the value of `name` is not going to change
// (that it is a "string literal type" and not just of type `string`)
]
Have a look at the concept of Type Narrowing.
Here is a playground for you to check it out.

You should type your array
const searchData: OneClass[] = [
{
'name': 'a'
},
{
'name': 'b'
},
];

If what you are doing is trying to create an instance of the class for each item in your array of objects, you need to map and call the constructor:
interface SearchDatum {
name: string;
}
const searchData: SearchDatum[] = [
{
'name': 'a'
},
{
'name': 'b'
},
];
class OneClass {
readonly name: string;
constructor({ name }: SearchDatum) {
this.name = name;
}
}
const classInstances: OneClass[] = searchData.map((datum) => new OneClass(datum));
Here is a Typescript playground link

Related

How do I create dynamic array in typescript?

I want to create a dynamic array in typescript in the following format
const display = [
{ id: 1, displayName: "Abc1" },
{ id: 2, displayName: "Abc2" },
{ id: 3, displayName: "Abc3" }
]
I have tried the following codes
const [display, SetDisplay] = useState([])
function createData(id: number, name: string) {
return { id, name };
}
SetDisplay(display.push(createData(1, "Abc1")))
But can not push data into the variable display. Getting error like
Argument of type '{ id: number; result: string; }' is not assignable to parameter of type 'never'.
Any information for resolving this would be helpful.
You should not mutate the state directly.
You can directly do a setState and destructure your previous array to add new data.
You can as well type your setState as follow <{id: number; name:string}>
const [display,setDisplay] = useState<{id: number; name:string}>([]);
function createData(id: number, name: string) {
setDisplay((prev) => [...prev, { id, name } ]);
}
Add the type to the ‍‍useState:
const [display,SetDisplay] =
useState<{id: number,name: string}[]>([]);

Typescript error using a variable string to locate the value in an object

I am trying to use as a variable to locate a value in an object, basically console.log(myobj.name) but use a variable instead of name e.g.
const myProperty = name:string
console.log(myObj[myProperty])
full details below (including interfaces)
The code runs but I get the following error in VSCODE.
Element implicitly has an 'any' type because expression of type 'string' can't be used to index type 'Details'.
below is the code the very last line is the one where I get the typescript error (using strict types)
interface Details {
id:number,
name:string,
email:string
}
interface Items {
[key: string]: Details[],
}
const items: Items = {
"blackberry":[
{
id: 1,
name: 'John Doe',
email: 'john#doe.de'
},{
id: 2,
name: 'Brad',
email: 'lorem#ipsum.com',
}
],
"orange":[{
id: 4,
name: 'Barry',
email: 'john#doe.de'
}
]
}
const myName:string = "name"
const myIx:string = "orange"
// console.log(items[myIx])
console.log(items[myIx][0].name)
console.log(items[myIx][0][myName]) // code runs but TS error here in VScode
You should use the correct type for myName:
const myName: keyof Details = "name"
This also has the advantage, that you get a compile error when you have a typo, e.g. this will fail:
const myName: keyof Details = "Name"
Typescript sees a string passed with object[str] as being able to all kinds of values. You can set the myIx to an enum to force it to be one of the actually existing keys within the interface or the quick and dirty fix can be to cast it to any like this (items[myIx][0] as any)[myName]

What is the best way for assigning 2 different type object arrays to eachother in typescript?

I want to assign 2 different type array to eachother attribute by attribute.
Can someone explain me what is the best way for this purpose? I am using the code below, but when I have too much attribute , it does not good look. How can I map attributes easily?
export interface ClassA {
Type: string;
Name: string;
}
export interface ClassB {
Typ: string;
Nm: string;
}
let items: ClassA[] = [
{ Type: 'T1', Name: 'N1'},
{ Type: 'T2', Name: 'N2'},
{ Type: 'T3', Name: 'N3'},
];
let items2:ClassB [] = [];
items.forEach((item, index) => {
let obj: ClassB = {Typ:item.Type, Nm:item.Name };
items2.push(obj);
});
console.log(items2);
Use map instead since you can map from one type to another type with it. With explicit type annotations, it also gives you inference and typechecking in the map predicate as well:
let items2: ClassB[] = items.map((item) => ({ Typ: item.Type, Nm: item.Name }));
Playground

'default object' to initialize nested objects on typescript?

I have the following object on typescript to control results of a sports game:
export interface IResult {
[day: string]: IResultDay;
}
interface IResultDay {
[matchId: string]: IMatch;
}
interface IMatch {
teams: ITeam[];
winner: ITeam;
winnerScore: number;
loserScore: number;
}
I build it this way because it allow me to filter the matches I want to see per "day" and per "matchId".
The problem is that when I want to build this object, I need to keep verifying if its not undefined on each level. If I don't do that, the following happens:
const result: IResult = {}; // init the first level
result['2020-09-30']['2020093012344321'] = {
teams: [
{
teamId: '1234',
teamName: 'Lakers'
},
{
teamId: '4321',
teamName: 'Miami Heat'
}
],
winner: {
teamId: '1234',
teamName: 'Lakers'
},
winnerScore: 117,
loserScore: 107
};
The error:
TypeError: Cannot set property '2020093012344321' of undefined
And it get's worse when I go deep on the nested object. Is there a way to build this object without initializing each level?
In python there's this trick on dictionaries that allow us to start multiple levels at the same time:
from collections import defaultdict
my_dict = defaultdict(lambda: defaultdict(dict))
I want something that does exactly the same thing (or something with the same behavior). It's really weird keep initializing each level before creating the object in did.
Is there something like that on javascript/typescript?
There's nothing built in, but you can use a Proxy to intercept the property accesses and insert a default value when a property doesn't exist. Maybe something like this:
function defaultDict<T>(cb: (k: PropertyKey) => T): { [k: string]: T } {
return new Proxy({} as any, {
get(target, p, receiver) {
if (!(p in target)) {
target[p] = cb(p);
}
return target[p];
}
})
}
I don't know if the callback cares about the key passed in, but it doesn't really matter either way. Then you can make result like this:
const result: IResult = defaultDict(() => ({}));
which really only needs to have a single defaultDict() since to set result[day][match] = ... you really only need result[day] to be defined. And then this behaves as you expect, I think:
result['2020-09-30']['2020093012344321'] = {
teams: [
{
teamId: '1234',
teamName: 'Lakers'
},
{
teamId: '4321',
teamName: 'Miami Heat'
}
],
winner: {
teamId: '1234',
teamName: 'Lakers'
},
winnerScore: 117,
loserScore: 107
};
That gives no error, and then this works:
for (let day in result) {
for (let match in result[day]) {
console.log(JSON.stringify(result[day][match]))
}
}
/* {"teams":[{"teamId":"1234","teamName":"Lakers"},{"teamId":"4321","teamName":"Miami Heat"}],
"winner":{"teamId":"1234","teamName":"Lakers"},"winnerScore":117,"loserScore":107} */
Playground link to code
Unfortunately, no, javascript doesn't really have anything to allow setting multiple nested levels of a dictionary all in one go.
JavaScript sadly can't do this. However you can achieve this using some dependencies such as lodash:
const _ = require('lodash');
const result: IResult = {};
_.set(result, ['2020-09-30', '2020093012344321'], {} /* replace {} with your value */);

Typescript: Copy One member of an Array Class into single array

I have array class of DocumentItemSelection below: new Array<DocumentItemSelection>. I want to copy just documentNumber class member into another Array<string>, while retaining same order.
What is a shorthand way of conducting this in Javascript/Typescript? Currently utilizing a for/foreach loop.
export class DocumentItemSelection {
documentNumber: string;
documentDate: Date;
isCurrentOwnerFlag: boolean;
}
You can use Array.prototype.map to do this for you. Assuming that your Array<DocumentItemSelection> is stored in a const called data, then you simply ensure that the callback will return the value from the key documentNumber:
const documentNumbers = data.map(datum => datum.documentNumber);
TypeScript will automatically infer the type for documentNumbers array without issue: it will type if as Array<string> (or string[]).
See proof-of-concept example on TypeScript playground.
You can do it this way :
export class AppComponent implements OnInit {
datas = [
{
id:0,
name: "first",
},
{
id:1,
name: "second",
},
{
id:2,
name: "third",
},
];
ngOnInit() {
const arrayOfName = this.datas.map(item => item.name); // Here
console.log('arrayOfName', arrayOfName);
}
}
.map will project what you return, so jut return the value you want.
Here is a repro on Stackblitz

Categories