Как рекурсивно проверять типы свойств в объекте

Я пишу функцию, которая принимает объект (A), сравнивает его с другим объектом (B) и создает новый объект (C). Объекты A и B симметричны (одинаковое количество свойств, одинаковые ключи), но тип их значений может различаться. Например: A.amount может быть «11», а B.amount — числом. Конечным результатом должен быть объект C, который имеет значения из A с типами из B.

В функции, которую я придумал, я перебираю все свойства объекта A, проверяя тип свойств объекта B с помощью оператора switch/case, применяя преобразование типов (например, .toString()) и добавляя исправленное свойство к объекту C. .

Я хотел бы, чтобы код был рекурсивным, но как только задействованы вложенные объекты, я не знаю, как получить свойства в B и создать эквивалент в C.

Пример объекта А:

const data = {
    a: "15",
    b: "foo",
    c: false,
    d: {
          da: 99,
          db: [{
                 dba: "1.2",
                 dbb: true
              }]
       }
    }

Пример объекта B:

const targetType = {
    a: 27,
    b: "foofoo",
    c: true,
    d: {
          da: "bar",
          db: [{
                 dba: 4,
                 dbb: false
              }]
       }
    }

Пример объекта C - значения из A, типы из B:

const finalObject = {
    a: 15,
    b: "foo",
    c: false,
    d: {
          da: "99",
          db: [{
                 dba: 1.2,
                 dbb: true
              }]
       }
    }

Моя функция:

//data = object A
//targetType = object B
export function typeConversion(data: any, targetType: any) {
  const resultObj = {};
  Object.keys(data).forEach((key) => {
    switch (typeof targetType[key]) {
      case 'string':
        resultObj[key] = data[key].toString();
        break;
      case 'boolean':
        resultObj[key] = data[key] ? 'Yes' : 'No';
        break;
      case 'number':
        resultObj[key] = Number(data[key]);
        break;
      //here is where it gets tricky:
      case 'object':
        if (Array.isArray(data[key])) {
          const dataArray: any = [];
          data[key].forEach((o) => {
            //all objs in the array have the same shape, hence comparing to [0]
            dataArray.push(typeConversion(o, targetType[key][0]));
          });
          resultObj[key] = dataArray;
        } else {
          const dataObj = {};
          Object.keys(data[key]).forEach((subkey) => {
            dataObj[subkey] = typeConversion(subkey, targetType[key][subkey]);
          });
          resultObj[key] = dataObj;
        }
        break;
    }
  });
  return resultObj;
}

console.info(typeConversion(data, targetType))

В тот момент, когда есть вложенный объект и typeConversion вызывается рекурсивно, ему не удастся найти путь к свойству в объекте B. Я мог бы добавить необязательный параметр в функцию для «родительского свойства», но это будет работать только для одного уровень глубины.

Если есть способ сделать это рекурсивным, это не может быть путем кодирования пути к targetType[like][this].

Пример игровой площадки TypeScript

Приветствуются все идеи, возможно, я неправильно ко всему отношусь.

Вы можете написать пример A, B и C?

Jackson 13.05.2022 10:38

Спасибо за проверку, добавлены примеры всех объектов

Dan-DH 13.05.2022 23:04

Если это действительно вопрос TypeScript (а не вопрос JavaScript), то код примера полон ошибок, не связанных с вашей проблемой. Предоставьте минимальный воспроизводимый пример, который четко демонстрирует проблему, с которой вы столкнулись. В идеале кто-то мог бы вставить код в автономную IDE, такую ​​как Площадка TypeScript (ссылка здесь!), и сразу же приступить к решению проблемы, не создавая ее заново. Таким образом, не должно быть псевдокода, опечаток, несвязанных ошибок или необъявленных типов или значений.

jcalz 13.05.2022 23:53

Добавлен пример детской площадки.

Dan-DH 15.05.2022 11:42
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
Улучшение производительности загрузки с помощью Google Tag Manager и атрибута Defer
В настоящее время производительность загрузки веб-сайта имеет решающее значение не только для удобства пользователей, но и для ранжирования в...
Безумие обратных вызовов в javascript [JS]
Безумие обратных вызовов в javascript [JS]
Здравствуйте! Юный падаван 🚀. Присоединяйся ко мне, чтобы разобраться в одной из самых запутанных концепций, когда вы начинаете изучать мир...
Система управления парковками с использованием HTML, CSS и JavaScript
Система управления парковками с использованием HTML, CSS и JavaScript
Веб-сайт по управлению парковками был создан с использованием HTML, CSS и JavaScript. Это простой сайт, ничего вычурного. Основная цель -...
JavaScript Вопросы с множественным выбором и ответы
JavaScript Вопросы с множественным выбором и ответы
Если вы ищете платформу, которая предоставляет вам бесплатный тест JavaScript MCQ (Multiple Choice Questions With Answers) для оценки ваших знаний,...
1
4
46
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Я внес некоторые изменения в вашу функцию, чтобы рекурсивно создать конечный объект. Хотя это не Typescript конкретная проблема, мне интересно, как это можно использовать :)

const transform = (data, targetType) => {
  let finalObject = {};
  const keys = Object.keys(data);
  
  for (const key of keys) {
    // If key is Array [], recursively add each element in Array
    if (data[key] instanceof Array) {
      finalObject[key] = [];
      for (let i = 0; i < data[key].length; i++) {
        const res = transform(data[key][i], targetType[key][i]);
        finalObject[key].push(res);
      }
    }
    // If key is Object {}, recursively add Object keys
    else if (data[key] instanceof Object) {
      finalObject[key] = transform(data[key], targetType[key]);
    }
    // If key is Primitive, we can directly add key
    else {
      switch (typeof targetType[key]) {
        case 'string':
          finalObject[key] = data[key].toString();
          break;
        case 'boolean':
          finalObject[key] = data[key] ? 'Yes' : 'No';
          break;
        case 'number':
          finalObject[key] = Number(data[key]);
          break;
      }
    }
  }

  return finalObject;
};

const data = {
  a: "15",
  b: "foo",
  c: false,
  d: {
    da: 99,
    db: [{
      dba: "1.2",
      dbb: true
    }]
  }
}

const targetType = {
  a: 27,
  b: "foofoo",
  c: true,
  d: {
    da: "bar",
    db: [{
      dba: 4,
      dbb: false
    }]
  }
}

const finalObject = transform(data, targetType);
console.info('Final Object : ', finalObject);

Благодарю вас! Сам бы я не догадался. Что касается варианта использования, последний объект используется для создания отчета Excel с xlsx-шаблон. Мы не полностью контролируем входные данные, поэтому нам нужно убедиться, что типы правильные (например, от 11 до 11). Я переключаю тег на JS, чтобы другим людям с похожей проблемой было легче найти.

Dan-DH 15.05.2022 15:30

Другие вопросы по теме