Constructor overload in TypeScript

前端 未结 16 2059
滥情空心
滥情空心 2020-11-28 00:42

Has anybody done constructor overloading in TypeScript. On page 64 of the language specification (v 0.8), there are statements describing constructor overloads, but there wa

16条回答
  •  孤城傲影
    2020-11-28 01:36

    Note: this was simplified and updated 4/13/2017 to reflect TypeScript 2.1, see history for TypeScript 1.8 answer.

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

    This is a very safe way to write for parameters that may not have all properties of the object defined. You can now safely write any of these:

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

    Compiled, you see that the optional parameters truly are optional, that avoids the pitfalls of a widely used (but error prone) fallback syntax of var = isOptional || default; by checking against void 0, which is shorthand for undefined:

    The Compiled Output

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

    Addendum: Setting default values: the wrong way

    The || (or) operator

    Consider the danger of ||/or operators when setting default fallback values as shown in some other answers. This code below illustrates the wrong way to set defaults. You can get unexpected results when evaluating against falsey values like 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)

    In my tests, using es6/typescript destructured object can be almost 90% faster than Object.assign. Using a destructured parameter only allows methods and properties you've assigned to the object. For example, consider this method:

    class BoxTest {
        public x?: number = 1;
    
        constructor(params: BoxTest = {} as BoxTest) {
            Object.assign(this, params);
        }
    }
    

    If another user wasn't using TypeScript and attempted to place a parameter that didn't belong, say, they might try putting a z property

    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')
    

提交回复
热议问题