Как использовать сеттеры в расширенных классах ImmutableJS Record - PullRequest
2 голосов
/ 11 июня 2019

Я хочу использовать неизменяемый для реализации моей доменной модели.Итак, я посмотрел, искал и нашел хороший часто используемый шаблон, основанный на расширении Records.Единственная проблема, с которой я столкнулся: я не могу заставить функцию .set или .merge работать как следует.

Давайте рассмотрим следующий пример:

const SpecificRecord = Record({id: 0, someProp: ''});

export default class SpecificClass extends SpecificRecord {

  id: number;
  someProp: string;

  constructor(id, someProp) {
    super({id, someProp});
  } 

  isSomePropFancy = () : boolean => {
    return this.someProp === 'fancy';
  }
}

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

const obj: SpecificClass = new SpecificClass(1, 'not-fancy');
console.log(obj.isFancy()); //prints out false
const newObj = obj.set('someProp', 'fancy'); //returns a Record -> should be SpecificClass
console.log(newObj.someProp) //prints out 'fancy'
console.log(newObj.isFancy()); //this fails: isFancy is not a function

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

Не для записи: сейчас я использую это, но я действительно очень не доволен этим решением:

//In SpecificClass I override:
set = (key, value): SpecificClass => {
  const values = super.toObject();
  values[key] = value;
  return new SpecificClass(values);
};

Ответы [ 2 ]

2 голосов
/ 13 июня 2019

Обычный совет для функций стрелок: «если сомневаетесь, используйте его».В этом случае это побивает рекорд фабрики.Просто измените его на обычную функцию:

const SpecificRecord = Record({id: 0, someProp: ''});
class SpecificClass extends Immutable.Record({id: 0, someProp: ''}) {
  constructor(id, someProp) {
    super({id, someProp});
  } 

  /* bad
  isFancy = () => {
    return this.someProp === 'fancy';
  }
  */

  // good
  isFancy() {
    return this.someProp === 'fancy';
  }
}

const obj = new SpecificClass(1, 'not-fancy');
console.log('fancy:', obj.isFancy()); //prints out false
const newObj = obj.set('someProp', 'fancy'); //returns a Record -> should be SpecificClass
console.log('new obj prop:', newObj.someProp) //prints out 'fancy'
console.log('is new obj fancy?', newObj.isFancy());
0 голосов
/ 10 июля 2019

ИМХО, методы экземпляра класса и записи действительно плохо сочетаются.

Методы записи (например, .set) не поддерживают цепочку прототипов, потому что они возвращают новую запись, как если бы вы имелиснова позвонил на завод.Проблема в том, что isSomePropFancy определено в SpecificClass.prototype, поэтому вы потеряете доступ к нему при создании новой записи.

Вы можете использовать переопределение метода, как у вас, для каждого метода записи (хотяЯ не думаю, что ваш будет работать так, как у вас):

const SpecificRecord = Record({id: 0, someProp: ''});

export default class SpecificClass extends SpecificRecord {

  id: number;
  someProp: string;

  constructor(id, someProp) {
    super({id, someProp});
  } 

  isSomePropFancy = () : boolean => {
    return this.someProp === 'fancy';
  }

  set = (key, value): SpecificClass => {
    const values = {...this, [key]: value};
    return new SpecificClass(values.id, values.someProp);
  };

  // also need to define merge, delete, etc.
}

или установить isSomePropFancy в записи как свойство:

const SpecificRecord = Record({
    id: 0,
    someProp: '',
    isSomePropFancy: (): boolean => this.someProp === 'fancy'
});

export default class SpecificClass extends SpecificRecord {

  id: number;
  someProp: string;
  isSomePropFancy: () => boolean;

  constructor(id, someProp) {
    super({id, someProp});
  } 
}

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

(например, new SpecificClass({id: 1, someProp: 'not-fancy'}) вместо new SpecificClass(1, 'not-fancy'))

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

...