如何将 Typescript class 对象转换为 Immutable.js 映射
How to convert a Typescript class object to an Immutable.js map
我正在尝试将 immutable.js 引入 Angular2 项目,但我在使用带有 immutable.js 的打字稿 classes 时遇到问题。
我正在尝试使用 Immutable.fromJS 函数将来自 class 的可变对象深度转换为不可变对象。不幸的是,尽管 fromJS 在 json 对象上运行良好,但如果给出了来自 class 的对象,它什么也不做(或者在尝试调用 .toJS() 到生成的对象时抛出)。
class Person {
public firstName: string;
}
let p = new Person();
p.firstName = 'Mike';
console.log(p);
let immutablePersonFail = Immutable.fromJS(p);
console.log(Immutable.Map.isMap(immutablePersonFail)); // returns false
let immutablePersonSuccess = Immutable.fromJS({firstName: 'Nick'});
console.log(Immutable.Map.isMap(immutablePersonSuccess)); // returns true
这是演示问题的 jsbin:
https://jsbin.com/yefeha/edit?js,console
试试这个:
let immutablePersonFail = Immutable.fromJS(Object.assign({}, p));
console.log(Immutable.Map.isMap(immutablePersonFail));
我在评论中提到了 中的更多信息。
编辑
这是一个选项:
class Base {
toObject(): any {
return Object.assign({}, this);
}
}
class Job extends Base {
public jobTitle: string;
}
class Person extends Base {
public firstName: string;
public jobs: Job[];
toObject(): any {
let obj = super.toObject();
obj.jobs = obj.jobs.map(job => job.toObject());
return obj;
}
}
另一个选项是区分数据和功能:
interface JobData {
title: string;
}
class Job {
private data: JobData;
getTitle(): string {
return this.data.title;
}
getData(): JobData {
return Immutable.fromJS(this.data);
}
}
interface PersonData {
firstName: string;
lastName: string;
jobs: JobData[];
}
class Person {
private data: PersonData;
public jobs: Job[];
getData(): JobData {
return Immutable.fromJS(this.data);
}
}
至于复杂度我不好说,要看你的业务逻辑是什么,怎么实现的。
如您所见,将 class 转换为不可变对象需要将 class 更改为不同的形式——常规 js 对象。对我来说,这里最好的解决方案是首先不要使用 class 。使用常规对象然后使用与之配合良好的模式会不那么痛苦。
interface Person {
firstName: string;
phoneNumbers: string[];
}
const p: Person = { firstName: "Mike", phoneNumbers: [] };
const immutablePersonFail = Immutable.fromJS(p);
console.log(Immutable.Map.isMap(immutablePersonFail)); // true
如果您最初使用 class 来帮助初始化对象,那么您可以使用函数或工厂 class 方法来帮助创建常规 js 对象:
function createPerson(firstName: string) {
const person: Person = {
firstName: firstName,
phoneNumbers: []
};
return Immutable.fromJS(person);
}
如果您最初使用 class 从数据中获取信息,那么您可以为此使用单独的 class:
class PersonHandler {
constructor(private person: Person) { // or typed as whatever fromJS returns
}
getFirstPhoneNumber() {
return this.person.phoneNumbers[0];
}
}
我有一个类似的问题,并通过从打字稿 类 创建不可变结构解决了这个问题,这也会将那些 children/attributes 转换为不可变对象。
例如:
class Car {
make: string;
model: string;
wheels: Wheel[]; // Is a collection of wheel objects (new Wheel() ..)
toImmutable() {
return Immutable.fromJS({
...omit(this, 'wheels'), // Lodash omit function, pick all other attributes except the wheels
wheels: this.wheels.map((w: Wheel) => w.toImmutable())
});
}
}
class Wheel {
size: number;
bolts: number;
toImmutable() {
return Immutable.fromJS(Object.assign({}, this));
}
}
// Later, something like:
const car = new Car();
car.addWheel(new Wheel());
car.addWheel(new Wheel());
// Convert to immutable object
const immutableCar = car.toImmutable();
immutableCar
现在生成一个不可变地图,它也有轮子作为不可变地图。
我正在尝试将 immutable.js 引入 Angular2 项目,但我在使用带有 immutable.js 的打字稿 classes 时遇到问题。
我正在尝试使用 Immutable.fromJS 函数将来自 class 的可变对象深度转换为不可变对象。不幸的是,尽管 fromJS 在 json 对象上运行良好,但如果给出了来自 class 的对象,它什么也不做(或者在尝试调用 .toJS() 到生成的对象时抛出)。
class Person {
public firstName: string;
}
let p = new Person();
p.firstName = 'Mike';
console.log(p);
let immutablePersonFail = Immutable.fromJS(p);
console.log(Immutable.Map.isMap(immutablePersonFail)); // returns false
let immutablePersonSuccess = Immutable.fromJS({firstName: 'Nick'});
console.log(Immutable.Map.isMap(immutablePersonSuccess)); // returns true
这是演示问题的 jsbin: https://jsbin.com/yefeha/edit?js,console
试试这个:
let immutablePersonFail = Immutable.fromJS(Object.assign({}, p));
console.log(Immutable.Map.isMap(immutablePersonFail));
我在评论中提到了
编辑
这是一个选项:
class Base {
toObject(): any {
return Object.assign({}, this);
}
}
class Job extends Base {
public jobTitle: string;
}
class Person extends Base {
public firstName: string;
public jobs: Job[];
toObject(): any {
let obj = super.toObject();
obj.jobs = obj.jobs.map(job => job.toObject());
return obj;
}
}
另一个选项是区分数据和功能:
interface JobData {
title: string;
}
class Job {
private data: JobData;
getTitle(): string {
return this.data.title;
}
getData(): JobData {
return Immutable.fromJS(this.data);
}
}
interface PersonData {
firstName: string;
lastName: string;
jobs: JobData[];
}
class Person {
private data: PersonData;
public jobs: Job[];
getData(): JobData {
return Immutable.fromJS(this.data);
}
}
至于复杂度我不好说,要看你的业务逻辑是什么,怎么实现的。
如您所见,将 class 转换为不可变对象需要将 class 更改为不同的形式——常规 js 对象。对我来说,这里最好的解决方案是首先不要使用 class 。使用常规对象然后使用与之配合良好的模式会不那么痛苦。
interface Person {
firstName: string;
phoneNumbers: string[];
}
const p: Person = { firstName: "Mike", phoneNumbers: [] };
const immutablePersonFail = Immutable.fromJS(p);
console.log(Immutable.Map.isMap(immutablePersonFail)); // true
如果您最初使用 class 来帮助初始化对象,那么您可以使用函数或工厂 class 方法来帮助创建常规 js 对象:
function createPerson(firstName: string) {
const person: Person = {
firstName: firstName,
phoneNumbers: []
};
return Immutable.fromJS(person);
}
如果您最初使用 class 从数据中获取信息,那么您可以为此使用单独的 class:
class PersonHandler {
constructor(private person: Person) { // or typed as whatever fromJS returns
}
getFirstPhoneNumber() {
return this.person.phoneNumbers[0];
}
}
我有一个类似的问题,并通过从打字稿 类 创建不可变结构解决了这个问题,这也会将那些 children/attributes 转换为不可变对象。
例如:
class Car {
make: string;
model: string;
wheels: Wheel[]; // Is a collection of wheel objects (new Wheel() ..)
toImmutable() {
return Immutable.fromJS({
...omit(this, 'wheels'), // Lodash omit function, pick all other attributes except the wheels
wheels: this.wheels.map((w: Wheel) => w.toImmutable())
});
}
}
class Wheel {
size: number;
bolts: number;
toImmutable() {
return Immutable.fromJS(Object.assign({}, this));
}
}
// Later, something like:
const car = new Car();
car.addWheel(new Wheel());
car.addWheel(new Wheel());
// Convert to immutable object
const immutableCar = car.toImmutable();
immutableCar
现在生成一个不可变地图,它也有轮子作为不可变地图。