Stack Overflow на русском Asked by hlearn on December 9, 2021
Есть иммутабельный объект с большим количеством свойств (в т.ч. вычисляемых):
class Test {
private _a: string;
private _b: string;
private _c: string;
constructor(a: string = '', b: string = '', c: string = '') {
this._a = a;
this._b = b;
this._c = c;
}
public get a(): string {
return this._a;
}
public get b(): string {
return this._b;
}
public get c(): string {
return this._c;
}
public get abc(): string {
return this._a + this._b + this._c;
}
}
В него нужно добавить функцию слияния объектов:
public static merge(...objs: Test[]): Test {
let t: Test = new Test();
let key: keyof Test;
for (let o of objs) {
for (key in o) {
if (o[key]) {
t[key] = o[key]; // (*)
}
}
}
return t;
}
Однако при копировании свойства (*) возникает ошибка: "Cannot assign to ‘a’ because it is a read-only property", т.к. keyof предоставляет открытые свойства, в т.ч. геттеры. Как можно скопировать private свойства без ручного перебора?
t._a = o._a;
t._b = o._b;
t._c = o._c;
Нашлось простое, но не лучшее решение - теперь есть риск опечатки, т.к. будет принято любое значение ключа. Но задача решена:
class Test {
private data: {[key: string]: string} = {};
constructor(a: string = '', b: string = '', c: string = '') {
this.data.a = a;
this.data.b = b;
this.data.c = c;
}
public static merge(...objs: Test[]): Test {
let t: Test = new Test();
for (let o of objs) {
for (let key in o.data) {
if (o.data[key]) {
t.data[key] = o.data[key];
}
}
}
return t;
}
}
Answered by hlearn on December 9, 2021
class Test {
constructor(
private _a: string,
private _b: string,
private _c: string,
) { }
get a(): string {
return this._a;
}
get b(): string {
return this._b;
}
get c(): string {
return this._c;
}
get abc(): string {
return this._a + this._b + this._c;
}
merge(...objList: any[]): this {
let key: any;
for (let obj of objList) {
for (key in obj) {
if (isKeyof(this, key)) {
/**
* k = `${key}` or `_${key}`
*/
let k = key;
// #region FIXME:
/** key is getter? */
if (isGetter(this, key)) {
// @ts-ignore
k = `_${key}`
if (!(k in this)) {
throw new TypeError('E_R_R')
}
}
// #endregion
this[k] = obj[key]; // (*)
}
}
}
return this;
}
}
function isGetter(obj: any, prop: string | number | symbol) {
const desc = Object.getOwnPropertyDescriptor(obj, prop)
return undefined !== desc && 'get' in desc
}
function isKeyof<T>(obj: T, k: any): k is (keyof T) {
return k in obj
}
Answered by qwabra on December 9, 2021
Тогда перепишите constructor немного
class Test {
private _a: string;
private _b: string;
private _c: string;
constructor(builder: Test) {
this._a = builder.a;
this._b = builder.b;
this._c = builder.c;
}
public get a(): string {
return this._a;
}
public get b(): string {
return this._b;
}
public get c(): string {
return this._c;
}
public get abc(): string {
return this._a + this._b + this._c;
}
}
Answered by Aziz Umarov on December 9, 2021
Get help from others!
Recent Questions
Recent Answers
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP