【问题标题】:How to convert a Typescript class object to an Immutable.js map如何将 Typescript 类对象转换为 Immutable.js 映射
【发布时间】:2017-06-03 16:17:24
【问题描述】:

我正在尝试将 immutable.js 引入 Angular2 项目,但在使用带有 immutable.js 的 typescript 类时遇到问题。

我正在尝试使用 Immutable.fromJS 函数将来自类的可变对象深度转换为不可变对象。不幸的是,虽然 fromJS 在 json 对象上工作得很好,但如果给定了来自某个类的对象,它什么也不做(或者在尝试调用 .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

【问题讨论】:

标签: typescript immutable.js


【解决方案1】:

试试这个:

let immutablePersonFail = Immutable.fromJS(Object.assign({}, p));
console.log(Immutable.Map.isMap(immutablePersonFail));

我在评论中引用了the other thread 中的更多信息。


编辑

这是一种选择:

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);
    }
}

至于复杂性,我不能说,这取决于你的业务逻辑是什么,以及你如何实现它。

【讨论】:

  • Object.assign 似乎确实解决了当类像上面那样平坦时的问题。但是有两个问题。首先,嵌套结构会发生什么(更新了我的 jsbin 以显示问题),因为 Object.assign 只执行浅拷贝。其次,在处理 ES6 类和 Immutable.js 时使用 Object.assign 是一种推荐的方法,因为每次从可变结构转移到不可变结构时都会增加额外的复杂性。
  • 检查我修改后的答案
【解决方案2】:

正如您所注意到的,将类转换为不可变对象需要将类更改为不同的形式——常规 js 对象。对我来说,最好的解决方案是一开始就不要使用课程。使用常规对象然后使用与这些对象配合良好的模式会不会那么痛苦。

interface Person {
    firstName: string;
    phoneNumbers: string[];
}

const p: Person = { firstName: "Mike", phoneNumbers: [] };   
const immutablePersonFail = Immutable.fromJS(p);
console.log(Immutable.Map.isMap(immutablePersonFail)); // true

如果您最初使用类来帮助初始化对象,那么您可以使用函数或工厂类方法来帮助创建常规 js 对象:

function createPerson(firstName: string) {
    const person: Person = {
        firstName: firstName,
        phoneNumbers: []
    };
    return Immutable.fromJS(person);
}

如果您最初使用类从数据中获取信息,那么您可以为此使用单独的类:

class PersonHandler {
    constructor(private person: Person) { // or typed as whatever fromJS returns
    }

    getFirstPhoneNumber() {
        return this.person.phoneNumbers[0];
    }
}

【讨论】:

  • 感谢大卫的详细回答。说实话,我认为你的方法是一个好主意,并继续在我的代码的一个分支中实现它。现在,在重构大量代码以在没有类的情况下工作后,我的所有测试再次通过,我可以肯定地说,不使用类感觉是一种倒退。我觉得打字稿提供的一些“自动化”已经消失了。不是 100% 肯定,但可能不会走这条路。不过答案很酷!
【解决方案3】:

我遇到了类似的问题,并通过从 typescript 类创建不可变结构来解决这个问题,该结构还将这些类的子/属性转换为不可变对象。

例如:

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 现在生成一个不可变地图,该地图也有轮子作为不可变地图。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2014-05-17
    相关资源
    最近更新 更多