2016-11-10 4 views
1

У меня есть класс по типу сценария:Машинопись - передать конструктору весь объект

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

Я хочу, чтобы заставить экземпляры классов иметь только свойства, объявление класса имеет.

Например, если я получаю от firebase объекта:

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

Итак, когда объект: {имя: «бен», цвет: «дБ»}, я хочу, чтобы результат:

currentChild = {"name":"ben"} 

Becouse "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Ï; 
    } 
    } 
} 

, но мой класс истина имеет много полей, и я хочу короткий код)

+0

Я думаю, что новая функция [keyof] (https://github.com/Microsoft/TypeScript/pull/11929) может быть удобной для вас. –

+0

@AlekseyL. Нет, потому что его проблема - время выполнения. –

ответ

2

У вас нет многие варианты здесь, потому что определения членов, которые вы делаете в классе перед конструктором, не переводятся в 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)

Это не проверял, так что я не уверен, что это работает, но если вы решили идти по этому пути, то это все, что вам нужно.

-1

По моему мнению, самый чистый способ создания экземпляров класса из произвольного объекта будет использовать деструктурирование.У вас еще есть задания для всех полей, но у вас есть (очень чистый) контроль над тем, что произойдет, если поле не существует, а также, какие поля вы будете назначать для ваших классов полей:

export class Child { 
    name:string 
    age:number 

    constructor({name = 'default name', age = 0} = {}) { 
    this.name = name 
    this.age = age 
    } 
} 

Теперь это позволяет создавать экземпляры из Object с или any с или каких-либо частичных литералов объектов, но при использовании литералов это не позволит вам добавить дополнительный материал, который, кажется, как это то, что вам нужно:

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, что генерируется на этом!