6

Перегрузка конструктора в TypeScript

14

Кому-нибудь удавалось реализовать перегрузку конструкторов в TypeScript? На странице 64 спецификации языка (версия 0.8) есть упоминания о перегрузке конструкторов, но примеры кода не представлены.

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

interface IBox {    
    x : number;
    y : number;
    height : number;
    width : number;
}

class Box {
    public x: number;
    public y: number;
    public height: number;
    public width: number;

    constructor(obj: IBox) {    
        this.x = obj.x;
        this.y = obj.y;
        this.height = obj.height;
        this.width = obj.width;
    }   

    constructor() {
        this.x = 0;
        this.y = 0;
        this.width = 0;
        this.height = 0;
    }
}

При запуске с помощью команды tsc BoxSample.ts возникает ошибка о дублировании определения конструктора, что вполне понятно. Буду признателен за любую помощь.

5 ответ(ов)

0

Я знаю, что это старый вопрос, но в версии 1.4 добавлены объединенные типы; используйте их для всех перегрузок функций (включая конструкторы). Пример:

class Foo {
    private _name: string | number;
    constructor(name: string | number) {
        this._name = name;
    }
}

const f1 = new Foo("bar");
const f2 = new Foo(1);

Таким образом, вы можете использовать объединенные типы для создания более универсальных конструкторов и функций, что делает код более гибким и понятным.

0

На самом деле, может быть, уже поздно для этого ответа, но вы теперь можете сделать так:

class Box {
    public x: number;
    public y: number;
    public height: number;
    public width: number;

    constructor();
    constructor(obj: IBox);
    constructor(obj?: IBox) {    
        this.x = !obj ? 0 : obj.x;
        this.y = !obj ? 0 : obj.y;
        this.height = !obj ? 0 : obj.height;
        this.width = !obj ? 0 : obj.width;
    }
}

Таким образом, вместо статических методов вы можете использовать приведённый выше подход. Надеюсь, это поможет вам!

0

Вы можете решить эту задачу, используя следующий код:

class Box {
  x: number;
  y: number;
  height: number;
  width: number;

  constructor(obj?: Partial<Box>) {
    Object.assign(this, obj);
  }
}

Использование Partial делает ваши поля (x, y, height, width) опциональными, что позволяет вам создавать экземпляры класса с различными комбинациями свойств.

Например, вы можете создать объект Box, передав только x и y, не указывая height и width, следующим образом: new Box({ x, y }).

0

Ваш класс Box пытается определить несколько реализаций конструктора. Однако, фактически используется только последняя перегрузка сигнатуры конструктора в качестве реализации конструктора.

В приведенном ниже примере обратите внимание, что реализация конструктора определена таким образом, что она не противоречит ни одной из предыдущих перегрузок сигнатур.

interface IBox {
    x: number;
    y: number;
    width: number;
    height: number;
}

class Box {
    public x: number;
    public y: number;
    public width: number;
    public height: number;

    constructor() /* Перегрузка сигнатуры */
    constructor(obj: IBox) /* Перегрузка сигнатуры */
    constructor(obj?: IBox) /* Реализация конструктора */ {
        if (obj) {
            this.x = obj.x;
            this.y = obj.y;
            this.width = obj.width;
            this.height = obj.height;
        } else {
            this.x = 0;
            this.y = 0;
            this.width = 0;
            this.height = 0;
        }
    }

    get frame(): string {
        console.log(this.x, this.y, this.width, this.height);
    }
}

new Box().frame; // 0 0 0 0
new Box({ x: 10, y: 10, width: 70, height: 120 }).frame; // 10 10 70 120

// Также можно написать класс Box следующим образом:
class Box {
    public x: number = 0;
    public y: number = 0;
    public width: number = 0;
    public height: number = 0;

    constructor() /* Перегрузка сигнатуры */
    constructor(obj: IBox) /* Перегрузка сигнатуры */
    constructor(obj?: IBox) /* Реализация конструктора */ {
        if (obj) {
            this.x = obj.x;
            this.y = obj.y;
            this.width = obj.width;
            this.height = obj.height;
        }
    }

    get frame(): string { ... }
}

Таким образом, следует помнить, что при использовании перегруженных конструкторов в TypeScript необходимо корректно реализовать последний конструктор, чтобы он соответствовал всем сигнатурам, определенным ранее.

0

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

export class Track {
   public title: string;
   public artist: string;
   public lyrics: string;

   constructor(track?: Track) {
     Object.assign(this, track);
   }
}

Имейте в виду, что этот код присвоит все свойства, переданные в track, даже если они не определены в классе Track. Это может привести к ситуации, когда объект Track будет содержать лишние свойства, которые не предусмотрены в классе. Если это допустимо для вашего случая использования, то такая реализация может быть оправдана, но если вам важно гарантировать, что в объекте будут только свойства, определенные в классе, вам следует использовать более строгий подход к присвоению свойств.

Чтобы ответить на вопрос, пожалуйста, войдите или зарегистрируйтесь