【问题标题】:Constructor overload in TypeScriptTypeScript 中的构造函数重载
【发布时间】:2012-09-24 00:43:23
【问题描述】:

有没有人在 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 运行时,它会抛出一个重复的构造函数定义——这很明显。任何帮助表示赞赏。

【问题讨论】:

  • 据我所知,它还不支持多个构造函数
  • 仍然不支持多个构造函数。刚试过:(
  • 查看这个答案:stackoverflow.com/a/58788876/2746447,只声明一次类字段

标签: typescript constructor overloading


【解决方案1】:

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

或两个重载,具有更通用的构造函数,如中,

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();
    constructor(obj: IBox); 
    constructor(obj?: IBox) {    
        this.x = obj?.x ?? 0
        this.y = obj?.y ?? 0
        this.height = obj?.height ?? 0
        this.width = obj?.width ?? 0;
    }   
}

Playground

【讨论】:

  • 实际上,应该可以让编译器生成 javascript 来在运行时确定采用了哪个重载。但这不太可能,因为他们的理念似乎是尽可能少地生成 javascript。
  • @remcoder,这永远是真的。某些类型的信息在运行时不可用。例如,生成的 JavaScript 中没有接口IBox 的概念。它可以用于类和内置类型,但我想考虑到这方面的潜在混淆,它被省略了。
  • 另一个非常重要的注意事项:虽然 TypeScript 已经不是类型安全的,但这进一步侵入了它。像这里所做的函数重载会丢失任何可以检查函数的属性。编译器将不再关心并假定返回的类型是正确的。
  • 是什么让这不是类型安全的?我们仍在确保类型为numberpublic x: number。安全性在于我们确保参数(如果传递)是正确的类型。
  • @nikkwong froginvasion 的观点是,使用这种技术 TypeScript 不会验证重载实现相对于重载的正确性。呼叫站点经过验证,但实施没有。虽然不是“类型安全”,但使用 froginvasion 的隐含定义,它确实将可归咎于类型错误的代码限制为重载实现。
【解决方案2】:

关于构造函数重载,一个不错的选择是将额外的重载实现为静态工厂方法。我认为它比在构造函数中检查所有可能的参数组合更具可读性和更容易。

在以下示例中,我们能够使用来自保险提供商的数据创建一个患者对象,该数据以不同的方式存储值。为了支持另一种用于患者实例化的数据结构,可以简单地添加另一种静态方法,以便在对提供的数据进行规范化后尽可能地调用默认构造函数。

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 中具有魔术参数的库编写声明。由于处理不同的可能参数集的所有繁重工作都由您完成,因此我认为在每种情况下使用重载而不是临时方法并没有多大优势。

【讨论】:

  • 如果您不想总是要求firstlastbirthday 出现在data 中,则可以使用(data: Partial<PersonData>)
  • 另外,构造函数的访问修饰符可以从public更改为private/protected,那么创建对象的唯一方法就是静态工厂方法。有时这可能非常有用。
【解决方案3】:

听起来您希望对象参数是可选的,并且对象中的每个属性也是可选的。在示例中,如提供的那样,不需要重载语法。我想在这里的一些答案中指出一些不好的做法。诚然,这并不是基本上编写box = { x: 0, y: 87, width: 4, height: 0 } 的最小可能表达,但这提供了您可能希望从所描述的类中获得的所有代码提示细节。此示例允许您使用一个、一些、全部、个参数调用一个函数,并且仍然获得默认值。

 /** @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;
     }
 }

需要添加方法? 一个冗长但更可扩展的替代方案: 上面的Box 类可以兼作接口,因为它们是相同的。如果您选择修改上述类,则需要为传入参数对象定义和引用一个新接口,因为Box 类不再与传入参数完全相同。注意在这种情况下表示可选属性的问号 (?:) 移动的位置。由于我们在类中设置默认值,因此它们保证存在,但它们在传入参数对象中是可选的:

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

编译后,您会看到只有在未定义可选值时才使用默认设置;它通过检查void 0undefined 的简写)来避免var = isOptional || default; 广泛使用(但容易出错)的回退语法的缺陷:

编译输出

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

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

||(或)运算符

在设置默认后备值时考虑||/或运算符的危险,如其他一些答案所示。下面的代码说明了设置默认值的错误方法。对 falsey 值(例如 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(this,params)

在我的测试中,使用 es6/typescript 解构对象 can be 15-90% faster than Object.assign。使用解构参数仅允许您分配给对象的方法和属性。例如,考虑这种方法:

class BoxTest {
    public x?: number = 1;

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

如果另一个用户没有使用 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')

【讨论】:

  • 我知道这是一个老话题,但 Ibox 铸件让我大吃一惊,你能向我解释一下它是如何工作的吗?
  • 我已经更新了我的答案,删除了 Typescript 1.8 编码遗留的多余强制转换。剩下的转换用于空对象(如果没有定义参数,{} 将成为默认对象;并且由于 {} 不验证为 Box,我们将其转换为 Box。以这种方式转换它允许我们创建一个未定义任何参数的新 Box。在您的 IDE 中,您可以输入我的示例以及 const box1 = new Box(); 行,您可以看到强制转换如何解决我们在使用场景中看到的一些错误消息。跨度>
  • @Benson BoxTest 示例包含错误。 TypeScript 编译器正确地抱怨构造函数的错误使用,但赋值仍然会发生。断言失败,因为 box.z is 实际上是 7 在您的代码中,而不是 undefined
  • 向 Box 类添加了一个方法,然后构造函数停止工作(编译时失败)。有什么想法吗?
  • @JeeShenLee 您可以使用方法将 Box 类扩展为新命名的类,或者为预期的参数创建一个接口。接口类型是从 Box 类借用的,因为类可以充当接口。使用您添加的方法,接口期望一个方法作为对象的一部分传入,因为该类作为接口执行双重职责。只需复制Box类的前五行,改成一个新名字的接口,比如interface BoxConfig { x?: number ...},然后改行constructor(obj: BoxConfig = {} as BoxConfig) {
【解决方案4】:

请注意,您还可以通过 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 = {x:0,y:0, height:0, width:0}) {    
        this.x = obj.x;
        this.y = obj.y;
        this.height = obj.height;
        this.width = obj.width;
    }   
}

编辑: 自 2016 年 12 月 5 日起,请参阅 Benson's answer 了解更精细的解决方案,以提供更大的灵活性。

【讨论】:

  • interface IBox extends Box 呢?
【解决方案5】:

更新 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 在他们的 cmets 中对我的回答提出了有效的观点。我建议读者看看BensonJoesnolflake 的答案,他们的答案比我的好。*

原始答案(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

【讨论】:

  • 这不是一个建设性的评论——但是,哇,这很难看。有点错过了 TypeScript 中 type 的安全性...
  • 这是构造函数重载吗?!不用了,谢谢!我宁愿为那个类实现一个静态工厂方法,确实很丑。
  • 我想今天我们可以有 dateOrYear: Date |号码,
  • 我认为在 c# 中使用对象初始化器之类的东西是一种非常好的方法。好的,您在某些情况下打开了门,但并非所有对象都应该有防护措施以防止初始化错误。 POCO 或 DTO 作为示例是此实现的良好候选者。我还将参数设置为 nullable 以允许像这样的空构造函数:args?: Partial
【解决方案6】:

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

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

【讨论】:

  • 难道name 字段的类型也不是string | number 而不是any
  • 你绝对可以这样做,是的,而且它可能会更加一致,但在这个例子中,它只会让你访问 .toString().valueOf(),在 Intellisense 中,所以对我来说,使用any 很好,但对每个人都是他/她自己的。
【解决方案7】:

实际上,这个答案可能为时已晚,但您现在可以这样做:

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

因此,您可以执行上述操作,而不是静态方法。希望对你有帮助!!!

【讨论】:

  • 太棒了!您必须在这里考虑,其他构造函数的每个新额外字段都应标记为可选;就像你已经为 obj? 所做的那样
  • 第二个构造函数constructor(obj: IBox);不是多余的吗?最后一个不是处理这两种情况吗?
【解决方案8】:

您可以通过以下方式处理:

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

Partial 将使您的字段 (x,y, height, width) 成为可选项,允许多个构造函数

例如:您可以在没有高度和宽度的情况下执行new Box({x,y})

【讨论】:

  • 我认为您仍然需要处理缺失项目的默认值。很容易做到。
  • constructor(obj?: Partial&lt;Box&gt;) +1
  • Partials 是一个很好的答案,但为什么要引入 lowdash?
  • @vegemite4me 你说得对,不需要 lodash。 Object.assign 就足够了
  • 小心,这个解决方案打破了类契约,因为Box 定义了所有属性都是强制性的,而这个解决方案允许它们是未定义的。
【解决方案9】:

您的Box 类正在尝试定义多个构造函数实现

只有最后一个构造函数重载签名被用作类构造函数实现

在下面的示例中,请注意 构造函数实现 的定义使其与前面的任何一个重载签名相矛盾。 p>

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 { ... }
}

【讨论】:

    【解决方案10】:

    如果可选的类型化参数足够好,请考虑以下代码,它可以在不重复属性或定义接口的情况下完成相同的操作:

    export class Track {
       public title: string;
       public artist: string;
       public lyrics: string;
    
       constructor(track?: Track) {
         Object.assign(this, track);
       }
    }
    

    请记住,这将分配在track 中传递的所有属性,即使它们未在Track 上定义。

    【讨论】:

      【解决方案11】:
      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;
          }
      }
      

      【讨论】:

      • 在这种情况下,将参数输入为{}而不是IBox不是更好吗?您已经在枚举属性约束...
      • @RoyTinker 是的,你是对的。基本上答案是错误的,我更新了它。
      【解决方案12】:

      我们可以使用guards模拟构造函数重载

      interface IUser {
        name: string;
        lastName: string;
      }
      
      interface IUserRaw {
        UserName: string;
        UserLastName: string;
      }
      
      function isUserRaw(user): user is IUserRaw {
        return !!(user.UserName && user.UserLastName);
      }
      
      class User {
        name: string;
        lastName: string;
      
        constructor(data: IUser | IUserRaw) {
          if (isUserRaw(data)) {
            this.name = data.UserName;
            this.lastName = data.UserLastName;
          } else {
            this.name = data.name;
            this.lastName = data.lastName;
          }
        }
      }
      
      const user  = new User({ name: "Jhon", lastName: "Doe" })
      const user2 = new User({ UserName: "Jhon", UserLastName: "Doe" })
      

      【讨论】:

        【解决方案13】:

        我使用以下替代方法来获取默认/可选参数和具有可变参数数量的“重载类型”构造函数:

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

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

        【讨论】:

          【解决方案14】:

          这是一个工作示例,您必须考虑每个具有更多字段的构造函数都应将额外字段标记为optional

          class LocalError {
            message?: string;
            status?: string;
            details?: Map<string, string>;
          
            constructor(message: string);
            constructor(message?: string, status?: string);
            constructor(message?: string, status?: string, details?: Map<string, string>) {
              this.message = message;
              this.status = status;
              this.details = details;
            }
          }
          

          【讨论】:

            【解决方案15】:

            正如@Benson 回答中所评论的,我在我的代码中使用了这个示例,我发现它非常有用。但是,当我尝试使用我的类变量类型进行计算时,我发现Object is possibly 'undefined'.ts(2532) 错误,因为问号导致它们属于AssignedType | undefined 类型。即使在以后的执行中处理未定义的情况或使用编译器类型强制 &lt;AssignedType&gt; 我无法摆脱错误,因此无法使 args 成为可选。我解决了为带有问号参数的参数创建一个单独的类型和没有问号的类变量。冗长,但有效。

            这是原始代码,在类method()中给出错误,见下文:

            /** @class */
            
            class Box {
              public x?: number;
              public y?: number;
              public height?: number;
              public width?: number;
            
              // The Box class can work double-duty as the interface here since they are identical
              // If you choose to add methods or modify this class, you will need to
              // define and reference a new interface for the incoming parameters object 
              // e.g.:  `constructor(params: BoxObjI = {} as BoxObjI)` 
              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
                const {
                  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;
              }
            
              method(): void {
                const total = this.x + 1; // ERROR. Object is possibly 'undefined'.ts(2532)
              }
            }
            
            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 });
            

            所以变量不能在类方法中使用。 如果像这样更正,例如:

            method(): void {
                const total = <number> this.x + 1;
            }
            

            现在出现这个错误:

            Argument of type '{ x: number; y: number; width: number; height: number; }' is not 
            assignable to parameter of type 'Box'.
            Property 'method' is missing in type '{ x: number; y: number; width: number; height: 
            number; }' but required in type 'Box'.ts(2345)
            

            好像整个参数包不再是可选的了。

            因此,如果创建了具有可选参数的类型,并且从可选中删除了类变量,我实现了我想要的,参数是可选的,并且能够在类方法中使用它们。解决方案代码下方:

            type BoxParams = {
              x?: number;
              y?: number;
              height?: number;
              width?: number;
            }
            
            /** @class */
            class Box {
              public x: number;
              public y: number;
              public height: number;
              public width: number;
            
              // The Box class can work double-duty as the interface here since they are identical
              // If you choose to add methods or modify this class, you will need to
              // define and reference a new interface for the incoming parameters object 
              // e.g.:  `constructor(params: BoxObjI = {} as BoxObjI)` 
              constructor(params: BoxParams = {} as BoxParams) {
                // Define the properties of the incoming `params` object here. 
                // Setting a default value with the `= 0` syntax is optional for each parameter
                const {
                  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;
              }
            
              method(): void {
                const total = this.x + 1;
              }
            }
            
            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 });
            

            感谢任何花时间阅读并尝试理解我要​​表达的观点的人的评论。

            提前致谢。

            【讨论】:

            • 是的,这正是在进行自定义时如何使用我的方法(构造函数上方的注释指向您在此处的确切解决方案)。一些人被它绊倒了——我从课堂上偷了界面——所以我很想修改我的答案。但我会把它留给历史,因为我的答案“按原样”是您在这里出色答案的必要参考点。
            • 好的,我明白了。感谢澄清
            【解决方案16】:

            一般来说对于 N 个重载,使用起来可能会更好:

            constructor(obj?: {fromType1: IType1} | {fromType2: IType2}) {    
                if(obj){
                  if(obj.fromType1){
                    //must be of form IType1
                  } else if(obj.fromType2){
                    //must have used a IType2
                  } else {
                    throw "Invalid argument 1"
                  }
                } else {
                  //obj not given
                }
            }   
            

            至少现在我们可以检查走哪条路线并采取相应的行动

            【讨论】:

              【解决方案17】:

              你应该记住...

              contructor()
              
              constructor(a:any, b:any, c:any)
              

              new()new("a","b","c")相同

              这样

              constructor(a?:any, b?:any, c?:any)
              

              同上,更灵活...

              new()new("a")new("a","b")new("a","b","c")

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2020-04-11
                • 1970-01-01
                • 2016-06-03
                • 1970-01-01
                • 1970-01-01
                • 1970-01-01
                • 2017-01-11
                相关资源
                最近更新 更多