Home > database >  How to trim all string properties of a class instance?
How to trim all string properties of a class instance?

Time:08-06

I have an instance of some class. Let's say this class is Person:

class Person {
    name?: string | null;
    age?: number | null;
    friends!: Person[];
    isLucky: boolean;
}

How to iterate over this instance and call trim() method on all properties that are strings? Because if I'm trying to do this:

(Object.keys(person) as (keyof typeof person)[]).forEach((key) => {
  const value = person[key];
  if (typeof value === 'string') {
    person[key] = value.trim();
  }
});

My friend Typescript shows this error:

Type 'string' is not assignable to type 'person[keyof person]'.

I want to write an all around method suitable for instances of different classes with many different properties. Is there a way to achieve this in Typescript? May be some typing magic?

CodePudding user response:

I would do it this way. Just cast it to any.

(Object.keys(person) as (keyof typeof person)[]).forEach((key) => {
  const value = person[key];
  if (typeof value === 'string') {
    (person as any)[key] = value.trim();
  }
});

CodePudding user response:

TypeScript isn't able to determine if the key is associated with a specific typed key from Person, only that it's one of them. So you'll get a type of never when accessing person[key] without any other specific checks on key.

The quickest answer is to narrow your key:

(Object.keys(person) as (keyof typeof person)[]).forEach((key) => {
  const value = person[key];
  if (key === 'name' && typeof value === 'string') {
    person[key] = value.trim();
  }
});

Alternatively you could do the .trim() in your class constructor and avoid this entirely, but it's unclear what the context is for your issue.

Generally I avoid doing a forEach to map an Object and might favor Object.from over an Object.entries with a .map() or reconsider the data structure entirely depending on what your actual use case might be.

  • Related