Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Typescript map types with different property names

I use Angular 6 + TypeScript 2.7.2 and I have a component that need ISelect[] type:

export interface ISelect {
    id: number;
    title: string;
}

So each time I call the component I need pass a ISelect[]. for example I have a IProject[] and I need to map it to ISelect[] In another example I have IClient[] and again I need map it to ISelect[], here is IProject:

export interface IProject {
    id: number;
    name: string;
    code: string;
    clientId: number;
    status: number;
    level: number;
    masterKey: number;
    parentId?: number;
}

I need to map it like this pseudocode.

 myprojects: IProject[];
 myselect: ISelect[] = myprojects.Foreach.Map<ISelect>(id: id, title: name);

Or:

export interface IClient {
    code: number,
    fullname: string,
    streetNumber: string,
    streetName: string,
    postalCode: string,
    city: string,
    isActive: boolean
}

And I need this map:

myClients: IClient[];
myselect: ISelect[] = myClients.Foreach.Map<ISelect>(id: code, title: fullname);

How could I do this mapping. I prefer to avoid have a for loop inside my source array. but I could have different mappings each time I need to condvert. any suggestion?

like image 657
Saeid Avatar asked Jul 18 '18 15:07

Saeid


3 Answers

You can use an object destructuring parameter to define your mapping in the function passed to .map():

myselect: ISelect[] = myprojects.map(({ id, name: title }) => ({ id, title }));

This approach also works for IClient like this:

myselect: ISelect[] = myClients.map(({ code: id, fullname: title }) => ({ id, title }));
like image 33
Patrick Roberts Avatar answered Sep 23 '22 12:09

Patrick Roberts


Something like this will work

myselect: ISelect[] = this.myprojects.map(p => { return <ISelect>{ id: p.id, title: p.name } });
like image 58
domfx Avatar answered Sep 22 '22 12:09

domfx


If you don't want to write mapping method every time you have new class that can be converted to ISelect, you can write a generic converter method.

Here is one attempt wherein you have to specify keys that will map to id and title of ISelect interface.

  convert<T, TK extends keyof T>(arr: T[], idKey: TK, titleKey: TK) : any[] {
    return arr.map( item => {
      return { id: item[idKey], title: item[titleKey] };
    });
  }

And call it with either IClient or IProject - type script will do some type checking for you.

You can use something like this for array of IClient

let arrOfClients: IClient[] = [
  {
     code: 1, 
    fullname: 'test', 
    streetNumber: '12', 
    streetName: 'street', 
    postalCode: '12', 
    city: 'Bangalore', 
    isActive: true 
  }
];
let converted: ISelect[] = convert(arrOfClients, "code", "fullname");

Similarly, you can use something like this for array of IProject

let converted: ISelect[] = convert(arrOfProjects, "id", "name");
like image 34
Wand Maker Avatar answered Sep 20 '22 12:09

Wand Maker