Как расширить универсальный интерфейс с помощью класса, который должен быть универсальным для перечислений? - PullRequest
3 голосов
/ 16 мая 2019

Я использую библиотеку для сериализации объектов, она поддерживает настраиваемые преобразователи для сериализации / десериализации данных.

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

export interface JsonCustomConvert<T> {
    serialize(data: T): any;
    deserialize(data: any): T;
}

Это то, что у меня сейчас есть:

@JsonConverter
export class MyEnumConverter implements JsonCustomConvert<MyEnumConverter> {
  serialize(val: MyEnumConverter): string {
    return MyEnumConverter[val];
  }
  deserialize(val: any): MyEnumConverter {
    const possibleValidEnum = (<any>MyEnumConverter)[val];
    if (possibleValidEnum === undefined) {
      throw Error();
    }
    return <MyEnumConverter>possibleValidEnum;
  }
}

Проблема, очевидно, в том, что вам нужен конвертер для каждого перечисления. Есть ли способ заставить это работать с использованием универсального типа накласс для любой перечислимой строки с индексом?

Нет смысла показывать примеры, которые я получил до сих пор, так как я изучаю язык, и любая попытка просто приводит к случайным ошибкам.

Редактировать:

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

https://stackblitz.com/edit/typescript-t2kdyx

1 Ответ

3 голосов
/ 03 июня 2019

Мы можем создать фабричную функцию, которая возвращает класс. Реализация будет одинаковой для всех перечислений, но фактическое перечисление будет передано в качестве параметра фабричной функции:

import {
  JsonObject,
  JsonProperty,
  JsonConvert,
  JsonConverter,
  JsonCustomConvert,
} from "json2typescript";

enum A {
  a = "aa",
  b = "bb"
}

enum X {
  x = "xx",
  z = "zz"
}

function createConverter<T extends Record<keyof T, string | number>>(e: T){
  const reverseLookup = {} as  Record<T[keyof T], keyof T>
  for (const key of Object.keys(e) as Array<keyof T>) {
    reverseLookup[e[key]] = key;
  }
  @JsonConverter
  class EnumConverter implements JsonCustomConvert<T[keyof T]> {
    serialize(val: T[keyof T]): keyof T {
      return reverseLookup[val];
    }
    deserialize(val: keyof T): T[keyof T] {
      const possibleValidEnum = e[val];
      if (possibleValidEnum === undefined) {
        throw Error();
      }
      return possibleValidEnum as T[keyof T];
    }
  }
  return EnumConverter;
}


const XEnumConverter = createConverter(X);
const AEnumConverter = createConverter(A);

@JsonObject("User")
class User {
  @JsonProperty("aEnum", AEnumConverter)
  aEnum: A = A.a;
  @JsonProperty("xEnum", XEnumConverter)
  xEnum: X = X.x;
}

const jsonObj = {
  "aEnum": "a",
  "xEnum": "x"
};

let jsonConvert: JsonConvert = new JsonConvert();
let user: User = jsonConvert.deserializeObject(jsonObj, User);
console.log(user); // User {aEnum: "aa", xEnum: "xx"}

let r: User = jsonConvert.serializeObject(user);
console.log(r); // {aEnum: "a", xEnum: "x"}
...