Объединение сокращений свойств параметров с Destructuring в TypeScript

В TypeScript, когда мы хотим автоматически создавать свойства в нашем классе из определения конструктора, мы можем воспользоваться сокращением параметров параметров, например:

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

    }
}

И тогда перекошенный Javascript будет:

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

Но если мы хотим получить объект в нашем конструкторе, это будет примерно так:

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

Так как TypeScript 1.5, мы можем воспользоваться деструктурированием, например:

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

Вопрос. Как скомбинировать стенографию параметров и Destructuring в TypeScript?

Я попытался определить public перед определением объекта, например:

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

    }
}

Пробовал определять его перед каждой переменной, например:

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

    }
}

Но я не имел успеха. Любые мысли?

Ответы

Ответ 1

В настоящее время нет способа сделать это коротко, поэтому самым близким вы можете объявить свойства longhand и назначить переменные из назначения деструктурирования:

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

Если вы это делаете... вы, вероятно, просто решите принять IPerson и назначьте его члены без использования деструктурирования в конструкторе вообще.

Ответ 2

Другая стратегия - использовать возможность назначать переменной другого имени. Это сокращает одно повторение в конструкторе.

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

Вы также можете перенести одно из определений в конструкторе на интерфейс.

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

Ответ 3

Если у вас есть доступ к Object.assign, это работает:

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

class Person extends PersonData{}

Но обратите внимание, что новые экземпляры будут заполнены чем-либо в args - вы не можете разделить только те ключи, которые хотите использовать.