Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TypeScript - pass to constructor entire object

I have a class at type script:

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

I want to force class instances to have only properties that class declaration has.

For example, if I get from firebase an object:

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

So when the object is: {name:"ben", color:"db"}, I want the result to be:

currentChild = {"name":"ben"}

Becouse "color" is not field of "child".

I tried this:

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

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

But it is not help. "currentChild" get all of the fields and attached them to the class instance.

(Of course, I can use the following code:

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

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

, but my truth class has many fields, and I want short code)

like image 425
user5260143 Avatar asked Nov 10 '16 06:11

user5260143


People also ask

What does Super do in TypeScript?

The super keyword is used to call the constructor of its parent class to access the parent's properties and methods.

How do you call a constructor in TypeScript?

You can call the base class constructor from the child class by using the super() which will execute the constructor of the base class. Example: Javascript.

Is TypeScript object oriented?

In TypeScript, we can use common object-oriented patterns. One of the most fundamental patterns in class-based programming is being able to extend existing classes to create new ones using inheritance.

Can a TypeScript class have multiple constructors?

In TypeScript, we cannot define multiple constructors like other programming languages because it does not support multiple constructors.


2 Answers

In my opinion the cleanest way to build your class instances from an arbitrary object would be using destructuring. You still have assignments for all your fields, but you have (very clean) control over what happens if the field doesn't exists, and also what fields you will assign to your classes fields:

export class Child {
  name:string
  age:number

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

Now this lets you create your instances from Objects or anys or any partial object literals, but when using literals it won't let you add extra stuff, which seems like is what you need:

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

Generated js will check for everything that you would check manually:

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

Try and see in the playground what is generated from this!

like image 133
Balázs Édes Avatar answered Nov 02 '22 01:11

Balázs Édes


What we want:

  • one time declare class fields
  • have methods in our class

Solution:

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 - root class

Dog - nested class

All works without typescript errors

like image 15
egor.xyz Avatar answered Nov 02 '22 03:11

egor.xyz