Как предоставить структурную информацию о динамически генерируемых JSON - PullRequest
1 голос
/ 11 апреля 2020

Я хотел бы опубликовать sh пакет NPM (написанный на Typescript), который выглядит следующим образом:

const networks = { main: 1, test: 2, dev: 3 }

const resource = {
  foo: {
    [networks.main]: "hello",
    [networks.test]: "there",
    [networks.dev]: "friend"
  },
  bar: {
    [networks.main]: "how",
    [networks.test]: "are",
    [networks.dev]: "you"
  },
  baz: {
    [networks.main]: "have a",
    [networks.test]: "good",
    [networks.dev]: "day"
  }
}

И я хочу убедиться, что пользователь может настроить сеть один раз, а не надо беспокоиться о том, в какой сети они находятся:

const myMainResource = getResourceFor(networks.main)
const myTestResource = getResourceFor(networks.test)
const myDevResource = getResourceFor(networks.dev)

console.log(myMainResource.foo) // "hello"
console.log(myTestResource.foo) // "there"
console.log(myDevResource.foo) // "friend"

Таким образом, вместо того, чтобы писать resource.foo[networks.main], они могут просто написать resource.foo и получить то же самое.

Реальный объект на самом деле гораздо больше вложен, например: alice.contracts.foo, bob.protocol.bar, et c. Но как хранятся данные, сеть всегда находится на конечном узле дерева.

Я уже написал функцию getResourceFor, и она работает, как и ожидалось, повторяя все ресурсы и заменяя сети (именно поэтому данные «генерируются» во время выполнения).

Но я также хочу, чтобы в редакторе автоматически выполнялась работа (с использованием кода VS). А поскольку объект создается динамически во время выполнения, редактор не может точно знать форму получающегося объекта JSON.

Каков наилучший способ приблизиться к этому?

Если вы хотите увидеть реальный код, это здесь: https://github.com/studydefi/money-legos

1 Ответ

0 голосов
/ 12 апреля 2020

Я закончил тем, что использовал этот ответ: Deep Omit с машинописью

Это очень грязно, но, по крайней мере, работает. Результат здесь:

type Primitive =
  | string
  | Function
  | number
  | boolean
  | Symbol
  | undefined
  | null;

type MappingToChangeFrom = {
  address: {
    [x: number]: string;
  };
};

type MappingToChangeTo = {
  address: string;
};

type DeepOmitHelper<T> = {
  [P in keyof T]: T[P] extends infer TP //extra level of indirection needed to trigger homomorhic behavior // distribute over unions
    ? TP extends Primitive
      ? TP // leave primitives and functions alone
      : TP extends any[]
      ? DeepOmitArray<TP> // Array special handling
      : TP extends MappingToChangeFrom // IF type equals to { address: { [networkIds: number]: string } }
      ? Omit<TP, "address"> & MappingToChangeTo // Change to { address: string }
      : DeepOmit<TP>
    : never;
};

type DeepOmit<T> = T extends Primitive ? T : DeepOmitHelper<T>;

type DeepOmitArray<T extends any[]> = {
  [P in keyof T]: DeepOmit<T[P]>;
};

type RawLegos = typeof rawLegos;
type RawLegosWithoutNetworkId = DeepOmit<RawLegos>;

const isValidObject = (obj: unknown) => typeof obj === "object" && obj !== null;

// Recursively goes through each field, and changes the address value to the specific value
// i.e. compound.cDai.address[mainnet] = 0x...
//      becomes:
//      compound.cDai.address = 0x....
export const changeAddressValue = (
  networkId: number,
  immutableObj: RawLegos,
): RawLegosWithoutNetworkId => {
  let obj = immutableObj as any;

  // recursive base case, stop here
  if (!isValidObject(immutableObj)) {
    return obj;
  }

  // desctructure the object to create new reference
  obj = { ...immutableObj };
  // iterating over the object using for..in
  for (const key in obj) {
    if (Array.isArray(obj[key])) continue; // ignore arrays (e.g. ABIs)
    if (!isValidObject(obj[key])) continue; // ignore non-valid objects

    if (key === "address") {
      obj[key] = obj.address[networkId] || null;
    } else {
      obj[key] = changeAddressValue(networkId, obj[key]);
    }
  }
  return obj;
};
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...