Home > Mobile >  Make an object for an object in typescript
Make an object for an object in typescript

Time:10-11

I am building a react-native / typescript project and I run into this problem:

I have a list of objects that I fetch from an API, and it looks something like this:

[{ qwe1: 'Bob', qwe2: 18 },
{ qwe1: 'James', qwe2: 19 }]

But I don't want to have those keys names for this object (qwe1, qwe2), and I also don't want to run throw all the objects and change all the keys.

So I thought to make an object that will hold all the keys of the original object but give nice access for better names for them, it's look something like that :

{
name: 'qwe1',
age: 'qwe2'
}

and then when I want to access the user's name for example I will do this:

myObject[objectKeyNames.name]

I also made a type for the object that look like this:

{qwe1: string; qwe2: number;}

But then an error was showed up saing that:

Element implicitly has an 'any' type because expression of type 'string' can't be used to index type '<the name of the type>'

I am really new to typescript and I don't really get this, I would be most grateful for your support.

Thanks in advance :)

CodePudding user response:

Define your objectKeyNames object to specifically reference the keys from the data object.

For example

interface ApiResult {
  qwe1: string;
  qwe2: number;
}

const objectKeyNames: {[key: string]: keyof ApiResult} = {
  name: "qwe1",
  age: "qwe2"
};

// ---

const myObject: ApiResult = {
  qwe1: "Bob",
  qwe2: 18
};

console.log(myObject[objectKeyNames.name]);

Now Typescript knows that any key in objectKeyNames will reference a valid property name from the API result.


As an aside, it's usually trivial to re-map one data format to another

const niceObjects = results.map(({ qwe1, qwe2 }) => ({
  name: qwe1,
  age: qwe2,
}));

CodePudding user response:

The whole point of TypeScript, as opposed to JavaScript, is type safety. In ordinary JavaScript, person.lastMane will silently give you undefined; TypeScript compiler will give you a compile-time warning that people don't have last manes. However, when you do person[attribute], where attribute is a string whose value cannot be known at compile-time, TypeScript must wash hands of it. It can't know if attribute will be "lastName", or if it will end up as "lastMane". So it goes "I don't know about this, this is on you."

In order to satisfy TypeScript, one thing you can do is have a lookup of accessors instead of a lookup of attribute names, so that you never need to dynamically look up an attribute by a string. Something like this:

interface APIPerson {
  qwe1: string;
  qwe2: number;
}

const personAccessors = {
  "name": (apiPerson: APIPerson) => apiPerson.qwe1,
  "age": (apiPerson: APIPerson) => apiPerson.qwe2,
};

const apiPerson: APIPerson = {
  qwe1: "John",
  qwe2: 25,
}

const personName = personAccessors.name(apiPerson);
console.log(personName);

EDIT: ...but Phil's solution is smarter :) I leave this up primarily because of the explanation of why you are getting the error.

  • Related