【问题标题】:TypeScript - pass to constructor entire objectTypeScript - 传递给构造函数整个对象
【发布时间】:2017-03-24 02:49:48
【问题描述】:

我在 type script 有一门课:

export class Child {
  name:string;
  age:number;
}

我想强制类实例只具有类声明所具有的属性。

例如,如果我从 firebase 获取一个对象:

myFirebaseService.getChild(id).then(function(child){
  var currentChild = new Child(child);
}) 

所以当对象是:{name:"ben", color:"db"}时,我希望结果是:

currentChild = {"name":"ben"}

因为“color”不是“child”的字段。

我试过了:

export class Child {
  name:string;
  age:number;

  constructor(tempChild:Child = null) {
    if (tempChild){
      for (var prop in tempChild) {
        this[prop] = tempChild[prop];
      }
    }
  }
}

但这无济于事。 "currentChild" 获取所有字段并将它们附加到类实例。

(当然我可以使用下面的代码:

export class Child {
  name:string;
  age:number;

  constructor(tempChild:Child = null) {
    if (tempChild){
      this.nam  = tempChild.name;
      this.age =tempChild.ageÏ;
    }
  }
}

,但是我的真值类有很多字段,我想要短代码)

【问题讨论】:

标签: typescript constructor copy-constructor


【解决方案1】:

您在这里没有太多选择,因为您在构造函数之前在类中所做的成员定义没有被翻译成javascript,编译器将它们排除在外:

class Child {
    name: string;
    age: number;

    constructor() {
        this.name = "name";
    }
}

编译成:

var Child = (function () {
    function Child() {
        this.name = "name";
    }
    return Child;
}());

如您所见,name 成员是那里唯一的成员,甚至它也仅在分配给时使用。

因为您在运行时需要成员的名称,所以您需要将它们放在一边,例如放在一个数组中:

class Child {
    private static MEMBERS = ["name", "age"];

    name: string;
    age: number;

    constructor(tempChild: Child = null) {
        if (tempChild) {
            for (var prop in tempChild) {
                if (Child.MEMBERS.indexOf(props) >= 0) {
                    this[prop] = tempChild[prop];
                }
            }
        }
    }
}

使用起来不太舒服,因此您可以使用装饰器。
例如:

function member(cls: any, name: string) {
    if (!cls.constructor.MEMBERS) {
        cls.constructor.MEMBERS = [];
    }

    cls.constructor.MEMBERS.push(name);
}

function isMember(cls: any, name: string): boolean {
    return cls.MEMBERS[name] != null;
}

class Child {
    @member
    name: string;

    @member
    age: number;

    constructor(tempChild: Child = null) {
        if (tempChild) {
            for (var prop in tempChild) {
                if (isMember(Child, prop)) {
                    this[prop] = tempChild[prop];
                }
            }
        }
    }
}

(code in playground)

它没有经过测试,所以我不确定它是否有效,但如果你决定这样做,那么它就是你需要的大部分。

【讨论】:

    【解决方案2】:

    在我看来,从任意对象构建类实例的最简洁方法是使用解构。您仍然有所有字段的分配,但是您可以(非常干净)控制如果该字段不存在会发生什么,以及您将分配给您的类字段的字段:

    export class Child {
      name:string
      age:number
    
      constructor({name = 'default name', age = 0} = {}) {
        this.name = name
        this.age = age
      }
    }
    

    现在这让您可以从 Objects 或 anys 或任何部分对象文字创建实例,但是当使用文字时,它不会让您添加额外的东西,这似乎是您需要的:

    const c0 = new Child({} as any /* as Object works as well */)
    const c1 = new Child({}) // Literal, will be using defaults
    const c2 = new Child() // No argument, using defaults only
    const c3 = new Child({ name: 'a', age: 1 })
    const c4 = new Child({ name: 'b', foo: 'bar'}) // error with foo
    

    生成的 js 将检查您手动检查的所有内容:

    define(["require", "exports"], function (require, exports) {
        "use strict";
        var Child = (function () {
            function Child(_a) {
                var _b = _a === void 0 ? {} : _a, _c = _b.name, name = _c === void 0 ? 'default name' : _c, _d = _b.age, age = _d === void 0 ? 0 : _d;
                this.name = name;
                this.age = age;
            }
            return Child;
        }());
        exports.Child = Child;
    });
    

    尝试在playground 中查看由此生成的内容!

    【讨论】:

    【解决方案3】:

    我们想要什么:

    • 一次性声明类字段
    • 在我们的类中有方法

    解决方案:

    class Animal {
      name: string = 'default value';
      group: string = 'default value';
    
      constructor(data: Partial<Animal> = {}) {
        Object.assign(this, data)
      }
    
      echo() {
        return `My name is ${this.name}, I'm from: ${this.group}`;
      }
    }
    
    class Dog extends Animal {
      echo() {
        return super.echo() + ' from Dog class';
      }
    }
    
    const dog = new Dog({name: 'Teddy'});
    console.log(dog.echo());
    

    Animal - 根类

    Dog - 嵌套类

    所有作品都没有打字错误

    【讨论】:

    • 此方案将this复制data的所有属性;如果我们想确保只复制类属性,最好的答案是 Balázs Édes one。
    猜你喜欢
    • 2014-06-04
    • 1970-01-01
    • 2012-07-09
    • 1970-01-01
    • 2011-10-24
    • 1970-01-01
    • 1970-01-01
    • 2013-09-13
    • 2020-07-27
    相关资源
    最近更新 更多