有人在TypeScript中做过构造函数重载吗?在语言规范(v 0.8)的第64页,有描述构造函数重载的语句,但没有给出任何示例代码。

我现在正在尝试一个非常基本的类声明;它是这样的,

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,它抛出一个重复的构造函数定义——这是显而易见的。任何帮助都是感激的。


当前回答

你可以通过以下方法来处理:

class Box {
  x: number;
  y: number;
  height: number;
  width: number;
  constructor(obj?: Partial<Box>) {    
     assign(this, obj);
  }
}

Partial将使你的字段(x,y,高度,宽度)可选,允许多个构造函数

例如:你可以新建Box({x,y})没有高度和宽度。

其他回答

更新2(2020年9月28日):这种语言在不断发展,所以如果你可以使用Partial(在v2.1中引入),那么这是我现在最喜欢的实现这一目标的方式。

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

   public constructor(b: Partial<Box> = {}) {
      Object.assign(this, b);
   }
}

// Example use
const a = new Box();
const b = new Box({x: 10, height: 99});
const c = new Box({foo: 10});          // Will fail to compile

更新(2017年6月8日):guyarad和snolflake在他们的评论中对我的回答提出了有效的观点。我建议读者看看Benson, Joe和snolflake的答案,他们的答案比我的更好

原答案(2014年1月27日)

另一个如何实现构造函数重载的例子:

class DateHour {

  private date: Date;
  private relativeHour: number;

  constructor(year: number, month: number, day: number, relativeHour: number);
  constructor(date: Date, relativeHour: number);
  constructor(dateOrYear: any, monthOrRelativeHour: number, day?: number, relativeHour?: number) {
    if (typeof dateOrYear === "number") {
      this.date = new Date(dateOrYear, monthOrRelativeHour, day);
      this.relativeHour = relativeHour;
    } else {
      var date = <Date> dateOrYear;
      this.date = new Date(date.getFullYear(), date.getMonth(), date.getDate());
      this.relativeHour = monthOrRelativeHour;
    }
  }
}

来源:http://mimosite.com/blog/post/2013/04/08/Overloading-in-TypeScript

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) {
        const { x, y, height, width } = { x: 0, y: 0, height: 0, width: 0, ...obj }
        this.x = x;
        this.y = y;
        this.height = height;
        this.width = width;
    }
}

我使用以下替代方法来获得默认/可选参数和“kind-of-overloaded”的构造函数,参数数量可变:

private x?: number;
private y?: number;

constructor({x = 10, y}: {x?: number, y?: number}) {
 this.x = x;
 this.y = y;
}

我知道这不是最漂亮的代码,但人们会习惯它。不需要额外的接口,它允许私有成员,这在使用接口时是不可能的。

It sounds like you want the object parameter to be optional, and also each of the properties in the object to be optional. In the example, as provided, overload syntax isn't needed. I wanted to point out some bad practices in some of the answers here. Granted, it's not the smallest possible expression of essentially writing box = { x: 0, y: 87, width: 4, height: 0 }, but this provides all the code hinting niceties you could possibly want from the class as described. This example allows you to call a function with one, some, all, or none of the parameters and still get default values.

 /** @class */
 class Box {
     public x?: number;
     public y?: number;
     public height?: number;
     public width?: number;     

     constructor(params: Box = {} as Box) {

         // Define the properties of the incoming `params` object here. 
         // Setting a default value with the `= 0` syntax is optional for each parameter
         let {
             x = 0,
             y = 0,
             height = 1,
             width = 1
         } = params;
         
         //  If needed, make the parameters publicly accessible
         //  on the class ex.: 'this.var = var'.
         /**  Use jsdoc comments here for inline ide auto-documentation */
         this.x = x;
         this.y = y;
         this.height = height;
         this.width = width;
     }
 }

Need to add methods? A verbose but more extendable alternative: The Box class above can work double-duty as the interface since they are identical. If you choose to modify the above class, you will need to define and reference a new interface for the incoming parameters object since the Box class no longer would look exactly like the incoming parameters. Notice where the question marks (?:) denoting optional properties move in this case. Since we're setting default values within the class, they are guaranteed to be present, yet they are optional within the incoming parameters object:

    interface BoxParams {
        x?: number;
         // Add Parameters ...
    }

    class Box {
         public x: number;
         // Copy Parameters ...
         constructor(params: BoxParams = {} as BoxParams) {
         let { x = 0 } = params;
         this.x = x;
    }
    doSomething = () => {
        return this.x + this.x;
        }
    }

无论你选择哪种方式来定义你的类,这种技术都提供了类型安全的护栏,同时还可以灵活地编写以下任何一种:

const box1 = new Box();
const box2 = new Box({});
const box3 = new Box({x:0});
const box4 = new Box({x:0, height:10});
const box5 = new Box({x:0, y:87,width:4,height:0});

 // Correctly reports error in TypeScript, and in js, box6.z is undefined
const box6 = new Box({z:0});  

编译后,您将看到如何仅在可选值未定义时使用默认设置;它避免了广泛使用(但容易出错)的回退语法var = isOptional || default的陷阱;通过检查void 0,它是undefined的缩写:

编译后的输出

var Box = (function () {
    function Box(params) {
        if (params === void 0) { params = {}; }
        var _a = params.x, x = _a === void 0 ? 0 : _a, _b = params.y, y = _b === void 0 ? 0 : _b, _c = params.height, height = _c === void 0 ? 1 : _c, _d = params.width, width = _d === void 0 ? 1 : _d;
        this.x = x;
        this.y = y;
        this.height = height;
        this.width = width;
    }
    return Box;
}());

附录:设置默认值:错误的方式

|| (or)操作符

在设置默认回退值时,如其他一些答案所示,请考虑||/或操作符的危险。下面的代码说明了设置默认值的错误方法。当你对0,",null, undefined, false, NaN等假值进行计算时,你可能会得到意想不到的结果:

var myDesiredValue = 0;
var result = myDesiredValue || 2;

// This test will correctly report a problem with this setup.
console.assert(myDesiredValue === result && result === 0, 'Result should equal myDesiredValue. ' + myDesiredValue + ' does not equal ' + result);

Object.assign (params)

在我的测试中,使用es6/typescript解构object可以比object .assign快15-90%。使用解构形参只允许您分配给对象的方法和属性。例如,考虑这个方法:

class BoxTest {
    public x?: number = 1;

    constructor(params: BoxTest = {} as BoxTest) {
        Object.assign(this, params);
    }
}

如果另一个用户没有使用TypeScript,并试图放置一个不属于TypeScript的参数,比如,他们可能会尝试放置一个z属性

var box = new BoxTest({x: 0, y: 87, width: 4, height: 0, z: 7});

// This test will correctly report an error with this setup. `z` was defined even though `z` is not an allowed property of params.
console.assert(typeof box.z === 'undefined')

我知道这是一个老问题,但1.4中的新功能是联合类型;对所有函数重载(包括构造函数)使用这些。例子:

class foo {
    private _name: any;
    constructor(name: string | number) {
        this._name = name;
    }
}
var f1 = new foo("bar");
var f2 = new foo(1);