Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Combining the Parameter Properties shorthand with Destructuring in TypeScript

EDIT

I logged an issue on TypeScript's Github repo and they're accepting PRs for implementing it.


In TypeScript, when we want to automatically create properties in our class from the constructor definition, we can take advantage of the Parameter Properties shorthand, e.g:

class Person {
    constructor(public firstName : string, public lastName : number, public age : number) {

    }
}

And then, the transpiled Javascript will be:

var Person = (function () {
    function Person(firstName, lastName, age) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
    return Person;
})();

But if we want to receive an object in our constructor, it would be something like:

interface IPerson {
    firstName : string,
    lastName : string,
    age: number
}

class Person {
    constructor(person : IPerson) {
        this.firstName = person.firstName;
        this.lastName = person.lastName;
        this.age = person.age;
    }
}

Since TypeScript 1.5, we can take advantage of destructuring, e.g:

class Person {
    constructor({firstName, lastName, age} : {firstName: string, lastName: string, age: number}) {
        this.firstName = firstName;
        this.lastName = lastName;
        this.age = age;
    }
}

Question: How to combine the Parameter Properties shorthand and Destructuring in TypeScript?

I've tried to define public before the object definition, e.g:

class Person {
    constructor(public {firstName, lastName, age} : {firstName: string, lastName: string, age: number}) {

    }
}

Tried to define it before each variable, e.g:

class Person {
    constructor({public firstName, public lastName, public age} : {firstName: string, lastName: string, age: number}) {

    }
}

But I had no success. Any thoughts?

like image 801
Buzinas Avatar asked Oct 19 '15 15:10

Buzinas


People also ask

How do you Destructure an object in typescript?

And this is destructuring an object. Let's take the following example: const user = { firstname: 'Chris', lastname: 'Bongers', age: 32 }; const { firstname, age } = user; By using this destructuring, we extract specific properties from an object.

How do you Destructure an array of objects in typescript?

To destructure an array in JavaScript, we use the square brackets [] to store the variable name which will be assigned to the name of the array storing the element. const [var1, var2, ...]

Can you give an example for Destructuring an object or an array?

In the first line, we are declaring a new variable studentsArr , and assigning it the value of an array of student names. Line 2 is where we destructure. In line 2 we declare three variables; first , second , and third . By declaring them on the left-hand side, we initiate destructuring.


3 Answers

If you have access to Object.assign, this works:

class PersonData {   firstName: string   constructor(args : PersonData) {     Object.assign(this, args)   } }  class Person extends PersonData{} 

But note new instances will be populated by anything in args--you can't strip out just the keys you want to use.

like image 184
elm Avatar answered Oct 27 '22 19:10

elm


There isn't currently a way to do this short-hand, so the closest you can get is to declare the properties longhand and assign the variables from the destructuring assignment:

class Person {     firstName: string;     lastName: string;     age: number;      constructor({firstName, lastName, age} : {firstName: string, lastName: string, age: number}) {         this.firstName = firstName;         this.lastName = lastName;         this.age = age;     } } 

If you are doing that... you'll probably just decide to accept an IPerson and assign its members without using destructuring in the constructor at all.

like image 29
Fenton Avatar answered Oct 27 '22 19:10

Fenton


Another strategy is to use the ability to assign to a variable of a different name. This cuts down on one repetition in the constructor.

class Person {
    firstName: string;
    lastName: string;
    age: number;

    constructor(args: { firstName: string, lastName: string, age: number, }) {
        ({
            firstName: this.firstName,
            lastName: this.lastName,
            age: this.age,
        } = args);
    }
}

You can also move one of the definitions in the constructor to an interface.

interface PersonConstructorArgs {
    firstName: string;
    lastName: string;
    age: number;
}
class Person {
    firstName: string;
    lastName: string;
    age: number;

    constructor(args: PersonConstructorArgs) {
        ({
            firstName: this.firstName,
            lastName: this.lastName,
            age: this.age,
        } = args);
    }
}

This will be useful when you have a hierarchy.

interface PersonConstructorArgs {
    firstName: string;
    lastName: string;
    age: number;
}
class Person {
    firstName: string;
    lastName: string;
    age: number;

    constructor(args: PersonConstructorArgs) {
        ({
            firstName: this.firstName,
            lastName: this.lastName,
            age: this.age,
        } = args);
    }
}
interface EmployeeConstructorArgs extends PersonConstructorArgs {
    manager: Person;
}
class Employee extends Person {
    manager: Person;

    constructor(args: EmployeeConstructorArgs) {
        super(args);
        ({
            manager: this.manager,
        } = args);
    }
}
like image 43
Schmalls Avatar answered Oct 27 '22 20:10

Schmalls