Как создать декоратор Typescript, который устанавливает все свойства класса как не перечисляемые на основе имени свойства, начинающегося с "_"? - PullRequest
0 голосов
/ 04 ноября 2019

Как получить декоратор класса Typescript для вызова метода, который устанавливает любое свойство или метод, начинающийся с "_", как не перечисляемое свойство (по сути, делая его закрытым для целей сериализации)?

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

class Base {
     constructor(data: any){
        Object.assign(this, data)
     }

     _setNonEnumerableProperties(){
        Object.keys(this).forEach(key => {
            if(key[0] === '_')
                Object.defineProperty(this, key, { enumerable: false })
        })
     }
}

А затем у меня есть класс User, подобный этому:

@nonEnumerablePrivateMembers
class User extends Base {
     public name: string
     public email: string
     private _active: boolean
}

И я создаю и JSON строковый экземпляр пользователя, как это:

const user = new User({name: 'John', email: 'john@example.com', _active: false})
const jsonUser = JSON.stringify(user)
console.log(jsonUser)

Я ожидаю, что результат будет следующим:

{ "name": "John", "email": "john@example.com" }

, а не это:

{ "name": "John", "email": "john@example.com", "_active": false }

Обратите внимание, что оно не включает свойство _active.

Мне нужно знать, как написать nonEnumerablePrivateMembers декоратор, который будет вызывать метод _setNonEnumerableProperties в Базовом классе для нового экземпляра расширенного класса.

Есть предложения?

Ответы [ 2 ]

1 голос
/ 04 ноября 2019

Переопределение конструктора выглядит так, как задумано:

interface Class<T> {
  new(...args: any[]): T
}

function nonEnumerablePrivateMembers<T extends Class<Base>>(cls: T): T {
  return class extends cls {
    constructor(...args: any[]) {
      super(...args);
      this._setNonEnumerableProperties();
    }
  }
}

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

0 голосов
/ 04 ноября 2019

Я уверен, что кто-то с лучшими навыками TypeScript может изменить это, чтобы быть немного чище, но на основе Документов по TypeScript вы можете получить что-то вроде этого:

function fixEnumerables<T extends { new (...args: any[]): {} }>(
  constructor: T
) {
  return class extends constructor {
    constructor(...data: any[]) {
      super(data);
      Object.assign(this, data[0]);
      Object.keys(this).forEach(key => {
        if (key[0] === "_") {
          console.log(`Freezing "${key}"`);
          Object.defineProperty(this, key, { enumerable: false });
        }
      });
    }
  };
}

@fixEnumerables
class User {
  public name: string;
  public email: string;
  private _active: boolean;
  constructor(data: any) {}
}

const x = new User({ name: "Sam", email: "email@example.com", _active: false });
console.log(JSON.stringify(x));

// Output
// Freezing "_active"
// {"name":"Sam", "email": "email@example.com"}

Блиц

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