sobrecarga de constructor a máquina de escribir

votos
216

Alguien ha hecho la sobrecarga de constructor a máquina de escribir. En la página 64 de la especificación del lenguaje (v 0.8), hay declaraciones que describen las sobrecargas del constructor, pero no había ningún código muestra dada.

Estoy probando una declaración de clase muy básica en este momento; se parece a esto,

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

Cuando corrió con BoxSample.ts TSC, que arroja una definición constructor duplicado - lo cual es obvio. Cualquier ayuda es apreciada.

Publicado el 03/10/2012 a las 06:48
fuente por usuario
En otros idiomas...                            


13 respuestas

votos
190

Mecanografiado le permite declarar sobrecargas, sino que sólo puede tener una implementación y que la aplicación debe tener una firma que es compatible con todas las sobrecargas. En el ejemplo, esto se puede hacer fácilmente con un parámetro opcional como en,

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

o dos sobrecargas con un constructor más general como en,

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?: any) {    
        this.x = obj && obj.x || 0
        this.y = obj && obj.y || 0
        this.height = obj && obj.height || 0
        this.width = obj && obj.width || 0;
    }   
}
Respondida el 03/10/2012 a las 07:14
fuente por usuario

votos
63

Tenga en cuenta que también se puede trabajar en torno a la falta de una sobrecarga a nivel de aplicación por medio de parámetros por defecto a máquina de escribir, por ejemplo:

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

Editar: A partir del 5 Dic '16, véase la respuesta de Benson por una solución más elaborada que permite una mayor flexibilidad.

Respondida el 09/10/2012 a las 07:29
fuente por usuario

votos
48

En cuanto constructor de sobrecarga una alternativa sería implementar las sobrecargas adicionales como métodos de fábrica estáticas . Creo que es más fácil de leer y menos confusa que probar sus argumentos de llamada. Aquí está un ejemplo sencillo:

class Person {
    static fromData(data: PersonData) {
        let { first, last, birthday, gender = 'M' } = data 
        return new this(
            `${last}, ${first}`,
            calculateAge(birthday),
            gender
        )
    }

    constructor(
        public fullName: string,
        public age: number,
        public gender: 'M' | 'F'
    ) {}
}

interface PersonData {
    first: string
    last: string
    birthday: string
    gender?: 'M' | 'F'
}


let personA = new Person('Doe, John', 31, 'M')
let personB = Person.fromData({
    first: 'John',
    last: 'Doe',
    birthday: '10-09-1986'
})

La sobrecarga de métodos a máquina de escribir no es real , digamos, ya que requeriría demasiado código generado por el compilador y el equipo central de tratar de evitar a toda costa. En la actualidad la principal razón de la sobrecarga de métodos para estar presente en el lenguaje es proporcionar una manera de escribir las declaraciones de bibliotecas con argumentos mágicos en su API. Puesto que usted tiene que hacer todo el trabajo pesado por sí mismo para manejar diferentes tipos de argumentos que no veo mucha ventaja en el uso de sobrecargas en lugar de métodos separados.

Respondida el 31/07/2016 a las 18:08
fuente por usuario

votos
38

Nota: esto se simplifica y se actualiza para reflejar 04/13/2017 mecanografiado 2.1, ver la historia de mecanografiado 1.8 respuesta.

Parece que usted desea que el parámetro del objeto a ser opcional, y también cada una de las propiedades del objeto a ser opcional. En el ejemplo, según lo previsto, no se necesita la sintaxis de sobrecarga. Yo quería señalar algunas malas prácticas en las algunas de las respuestas aquí. Por supuesto, no es la expresión más pequeña posible de escribir en esencia box = { x: 0, y: 87, width: 4, height: 0 }, pero esto ofrece todas las sutilezas sugerencias para el código que pueda desear de la clase como se describe. Este ejemplo le permite llamar a una función con uno, algunos, todos, o ninguno de los parámetros y aún así obtener los valores por defecto.

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

     // The class can work double-duty as the interface here since they are identical
     // Alternately, reference your own interface, e.g.:  `...BoxI = {} as BoxI` 
     constructor(obj: Box = {} as Box) {

         // Define the properties of the incoming `obj` object here. 
         // Setting a default value with the `= 0` syntax is optional for each parameter
         let {
             x = 0,
             y = 0,
             height = 0,
             width = 0
         } = obj;

         /** Use jsdoc comments here for inline ide auto-documentation */
         this.x = x;
         this.y = y;
         this.height = height;
         this.width = width;
     }
 }

Esta es una forma muy segura de escribir para los parámetros que pueden no tener todas las propiedades del objeto definido. Ahora puede escribir con seguridad alguna de estas:

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

Compilado, se ve que los parámetros opcionales verdaderamente son opcionales, que evita las trampas de un ampliamente utilizado (pero propenso a errores) sintaxis de repliegue de var = isOptional || default;chequeando contra void 0, que es la abreviatura de undefined:

La salida compilada

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

Adición: Configuración de los valores por defecto: el camino equivocado

El ||(o) operador

Considere el peligro de ||/ o operadores de la hora de establecer los valores de retorno predeterminados como se muestra en algunas otras respuestas. Este código siguiente ilustra el camino equivocado para establecer los valores predeterminados. Puede obtener resultados inesperados cuando se evalúa contra Falsey valores como 0, '', null, indefinido, falso, 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 (esto, obj)

En mis pruebas, utilizando objetos ES6 / mecanografiado desestructurado puede ser casi un 90% más rápido que Object.assign . El uso de un parámetro desestructurada sólo permite métodos y propiedades que ha asignado al objeto. Por ejemplo, considere este método:

class BoxTest {
    public x?: number = 1;

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

Si otro usuario no estaba usando mecanografiado e intentó colocar un parámetro que no le pertenecía, por ejemplo, puede ser que trate de poner una zpropiedad

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 obj.
console.assert(typeof box.z === 'undefined')
Respondida el 05/12/2016 a las 11:30
fuente por usuario

votos
32

Sé que esto es una vieja pregunta, pero de nuevo en 1.4 es tipos de unión; utilizar estas para todas las sobrecargas de función (incluyendo constructores). Ejemplo:

class foo {
    private _name: any;
    constructor(name: string | number) {
        this._name = name;
    }
}
var f1 = new foo("bar");
var f2 = new foo(1);
Respondida el 04/02/2015 a las 18:28
fuente por usuario

votos
20

Actualización (8 de junio del 2017): guyarad y snolflake hacer puntos válidos en sus comentarios a continuación a mi respuesta. Yo recomendaría a los lectores miran las respuestas de Benson , Joe y snolflake que tienen respuestas mejores que la mía.

Respuesta original (27 de enero de 2014)

Otro ejemplo de cómo lograr la sobrecarga de constructor:

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

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

Respondida el 27/01/2014 a las 17:02
fuente por usuario

votos
3

En el caso en el que un parámetro opcional, a máquina es lo suficientemente bueno, considere el siguiente código que realiza la misma sin repetir las propiedades o la definición de una interfaz:

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

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

Tenga en cuenta que esto asignar todas las propiedades aprobadas en track, víspera si no están definidos en Track.

Respondida el 05/11/2016 a las 21:22
fuente por usuario

votos
1

Puede manejar esto:

import { assign } from 'lodash'; // if you don't have lodash use Object.assign
class Box {
    x: number;
    y: number;
    height: number;
    width: number;
    constructor(obj: Partial<Box> = {}) {    
         assign(this, obj);
    }
}

Parcial hará que sus campos (x, y, altura, anchura) opcionales, permitiendo que varios constructores

por ejemplo: se puede hacer new Box({x,y})sin la altura y la anchura.

El = {}se encargará de valor Falsy como indefinido, null, etc, y entonces usted puede hacernew Box()

Respondida el 11/09/2018 a las 09:36
fuente por usuario

votos
1

Otra versión como al código de @ ShinNoNoir, utilizando los valores por defecto y la sintaxis de propagación:

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

    constructor({x, y, height, width}: IBox = { x: 0, y: 0, height: 0, width: 0 }) {
        this.x = x;
        this.y = y;
        this.height = height;
        this.width = width;
    }
}
Respondida el 30/11/2016 a las 02:11
fuente por usuario

votos
0

Yo uso la siguiente alternativa para conseguir default / params opcionales y "de tipo de sobrecarga" Constructores con número variable de params:

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

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

Yo sé que no es el código más bonito siempre, pero uno se acostumbra a ella. No hay necesidad de que el interfaz adicional y permite a los miembros privados, que no es posible cuando se utiliza la interfaz.

Respondida el 20/09/2019 a las 14:28
fuente por usuario

votos
0

En realidad, podría ser demasiado tarde para esta respuesta, pero ahora se puede hacer esto:

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

así que en vez de los métodos estáticos que puede hacer lo anterior. ¡¡¡Espero que te ayude!!!

Respondida el 26/05/2019 a las 23:31
fuente por usuario

votos
0

Podemos simular la sobrecarga del constructor usando guardias

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" })
Respondida el 27/03/2019 a las 00:18
fuente por usuario

votos
0

Usted debe tenido en cuenta que ...

contructor ()

constructor (a: cualquier, b: cualquiera, c: cualquier)

Es lo mismo de

nuevo () o nuevo ( "a", "b", "c")

Así

constructor (a:? cualquier, b:? cualquier, c:? cualquier) es el mismo arriba y es más flexible ...

nuevo () o nuevo ( "a") o nuevo ( "a", "b") o nuevo ( "a", "b", "c")

Respondida el 02/06/2018 a las 11:15
fuente por usuario

Cookies help us deliver our services. By using our services, you agree to our use of cookies. Learn more