Typescript: лучший способ перебрать объект и изменить значения свойств - PullRequest
1 голос
/ 01 мая 2020

У меня есть класс машинописи, который содержит этот метод:

 updatePropertiesValues()
{
    for (let key in this) {
        if (typeof this[key] == "string") {
            this[key] = "test";
        }
    }
}

Как видите, я хочу заменить все значения свойств типа string. Это работает, но компилятор жалуется: Type '"test"' is not assignable to type 'this[Extract<keyof this, string>]'. Конечно, у меня есть много свойств в этом объекте, поэтому я не хочу делать это одно за другим.

Как я могу сделать это без получения компилятора жалуется?

Ответы [ 2 ]

1 голос
/ 01 мая 2020

Безусловно, вам проще всего использовать утверждение типа . Это вы говорите компилятору не беспокоиться о проверке безопасности типов и что вы сами проверили его и утверждаете , что это безопасно:

for (let key in this) {
  if (typeof this[key] == "string") {
    this[key] = "test" as any; // assertion
    this[key] = "test" as any as this[typeof key]; // or this one
  }
}

Обратите внимание, что такое утверждение представляет переход ответственности за проверку безопасности типов от компилятора к вам. Вы можете легко l ie обратиться к компилятору с утверждением типа, а затем столкнуться с проблемами во время выполнения без какого-либо предупреждения от доверчивого компилятора:

    this[key] = 123 as any as this[typeof key]; // ? evil liar

Так что будьте осторожны.


Попытка заставить компилятор проверить безопасность типов здесь без какого-либо утверждения - трудная задача, и, вероятно, она того не стоит. Если вам интересно, я мог бы go подробно рассмотреть это, но эскиз:

  • this тип похож на Параметр типа generi c, и, следовательно, он не сужается при анализе потока управления (см. microsoft / TypeScript # 13995 ), как это делает тип, не являющийся родом c.

  • A for..in l oop или Object.keys() не сужает ключи до известных ключей итерированного объекта, поскольку объекты могут иметь больше свойств, чем знает компилятор (см. этот комментарий ).

  • Если вы не знаете точного литерального ключа для key, индексированный набор свойств, такой как this[key] = ..., в конечном итоге трактует тип свойства как пересечение из все возможные типы свойств (см. microsoft / TypeScript # 30769 ). Это безопаснее, но мешает многим обычным кодам, таким как this[key] = this[key].

Все это работает против вас, и самое простое, что можно сделать, это просто утверждать и двигаться дальше. Вы можете попытаться преобразовать свой код в вещи, которые компилятор считает безопасными, но это, возможно, более запутанно, чем просто утверждение типа.


Когда вы говорите, что не хотите выполнять каждое свойство одно за другим , вы можете попробовать опцию «посреди дороги», где вы упоминаете имена свойств дважды, но делаете установку только один раз:

// enumerate keys whose properties can be strings and set them
(["a", "d"] as const).forEach(k => this[k] = "test");

Если это компилируется без ошибок, это потому, что компилятор знает, что a и d свойства вашего класса являются строками. Он не идеален, но он является более безопасным шрифтом.


Хорошо, надеюсь, это поможет; удачи!

Детская площадка ссылка на код

0 голосов
/ 01 мая 2020

вы можете попробовать следующим образом

interface LooseObject {
    [key: string]: any
}

class A {

      prop1: string
      prop2: number
      prop3 = "1";

      constructor() {
            this.prop1 = "";
            this.prop2 = -1;
      }

      updatePropertiesValues() {
            for (var key in this) {
                  if (this.hasOwnProperty(key)) {
                        if (typeof this[key] == "string") {
                              const target = this as LooseObject;
                              target[key] = "test";
                        }
                  }
            }
      }
}

машинопись детская площадка

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...