如何在 ImmutableJS Record 的扩展 类 上使用 setter
How to use setters on extended classes of ImmutableJS Record
我想使用不可变来实现我的领域模型。所以我查看并搜索并找到了一个基于记录扩展的很好的常用模式。
我遇到的唯一问题是:我无法让 .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
我的问题是:我们如何覆盖或任何解决方案让我们更新记录的扩展,同时保持正确的 class 及其所有方法?
不公开:我现在正在使用这个,但我真的很不满意这个解决方案:
//In SpecificClass I override:
set = (key, value): SpecificClass => {
const values = super.toObject();
values[key] = value;
return new SpecificClass(values);
};
箭头函数的常用建议是"when in doubt, use it"。在这种情况下,它打破了唱片工厂。只需将其更改为常规函数即可:
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());
恕我直言,class 实例方法和记录确实不能很好地结合。
Record 方法(如 .set
)不维护原型链,因为它们 return 一个新的 Record,就像您再次调用工厂一样。问题是 isSomePropFancy
是在 SpecificClass.prototype 上定义的,因此在创建新记录时您将无法访问它。
您可以像对每个 Record 方法一样使用方法覆盖(尽管我认为您的方法不会像您拥有的那样工作):
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 和 Records,我说服我的团队,完全不将 Record 类型包装在 classes 中,只输入工厂 as-is.
我想使用不可变来实现我的领域模型。所以我查看并搜索并找到了一个基于记录扩展的很好的常用模式。
我遇到的唯一问题是:我无法让 .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
我的问题是:我们如何覆盖或任何解决方案让我们更新记录的扩展,同时保持正确的 class 及其所有方法?
不公开:我现在正在使用这个,但我真的很不满意这个解决方案:
//In SpecificClass I override:
set = (key, value): SpecificClass => {
const values = super.toObject();
values[key] = value;
return new SpecificClass(values);
};
箭头函数的常用建议是"when in doubt, use it"。在这种情况下,它打破了唱片工厂。只需将其更改为常规函数即可:
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());
恕我直言,class 实例方法和记录确实不能很好地结合。
Record 方法(如 .set
)不维护原型链,因为它们 return 一个新的 Record,就像您再次调用工厂一样。问题是 isSomePropFancy
是在 SpecificClass.prototype 上定义的,因此在创建新记录时您将无法访问它。
您可以像对每个 Record 方法一样使用方法覆盖(尽管我认为您的方法不会像您拥有的那样工作):
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 和 Records,我说服我的团队,完全不将 Record 类型包装在 classes 中,只输入工厂 as-is.