有人在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,它抛出一个重复的构造函数定义——这是显而易见的。任何帮助都是感激的。
正如chuckj所说,简单的答案是一个可选形参,但是如果我们想用多个形参重载构造函数,或者我们想改变形参顺序,该怎么办呢?
事实证明,构造函数可以像函数一样重载:
class FooBar {
public foo?: number;
public bar?: string;
// Constructor A
constructor(foo: number, bar?: string);
// Constructor B
constructor(bar: string, foo?: number);
// Constructor C
constructor(bar: string);
// Constructor D
constructor(foo: number);
// Constructor E
constructor();
constructor(...args: any[]) {
switch (args.length) {
case 2:
if (typeof args[0] === "number") {
this.foo = args[0];
this.bar = args[1];
} else {
this.bar = args[0];
this.foo = args[1];
}
break;
case 1:
if (typeof args[0] === "number") {
this.foo = args[0];
} else {
this.bar = args[0];
}
}
console.log(this.foo, this.bar);
}
}
const fooBarConstructorA = new FooBar("150", 25);
const fooBarConstructorB = new FooBar(25, "150");
const fooBarConstructorC = new FooBar("150");
const fooBarConstructorD = new FooBar("150");
const fooBarConstructorE = new FooBar();
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() /* Overload Signature */
constructor(obj: IBox) /* Overload Signature */
constructor(obj?: IBox) /* Implementation Constructor */ {
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
// You could also write the Box class like so;
class Box {
public x: number = 0;
public y: number = 0;
public width: number = 0;
public height: number = 0;
constructor() /* Overload Signature */
constructor(obj: IBox) /* Overload Signature */
constructor(obj?: IBox) /* Implementation Constructor */ {
if (obj) {
this.x = obj.x;
this.y = obj.y;
this.width = obj.width;
this.height = obj.height;
}
}
get frame(): string { ... }
}
关于构造函数重载,一个好的选择是将额外的重载实现为静态工厂方法。我认为它比在构造函数中检查所有可能的参数组合更易于阅读和更容易。
在下面的例子中,我们能够使用来自保险提供商的数据创建一个患者对象,这些数据存储的值不同。为了支持患者实例化的另一种数据结构,可以简单地添加另一个静态方法,以便在规范化所提供的数据后尽可能地调用默认构造函数。
class Patient {
static fromInsurance({
first, middle = '', last,
birthday, gender
}: InsuranceCustomer): Patient {
return new this(
`${last}, ${first} ${middle}`.trim(),
utils.age(birthday),
gender
);
}
constructor(
public name: string,
public age: number,
public gender?: string
) {}
}
interface InsuranceCustomer {
first: string,
middle?: string,
last: string,
birthday: string,
gender: 'M' | 'F'
}
const utils = { /* included in the playground link below */};
{// Two ways of creating a Patient instance
const
jane = new Patient('Doe, Jane', 21),
alsoJane = Patient.fromInsurance({
first: 'Jane', last: 'Doe',
birthday: 'Jan 1, 2000', gender: 'F'
})
console.clear()
console.log(jane)
console.log(alsoJane)
}
你可以在TS Playground查看输出
TypeScript中的方法重载并不是真的,因为它需要太多的编译器生成的代码,而TS的设计就是为了尽量避免这种情况。方法重载的主要用例可能是为API中有神奇参数的库编写声明。由于处理不同可能的参数集的所有繁重工作都是由您完成的,因此我不认为在每种场景中使用重载而不是特别方法有多大优势。