sobrecarga - typescript static class
Sobrecarga del constructor en TypeScript (10)
A otra versión le gusta el código de @ShinNoNoir, usando valores predeterminados y 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;
}
}
¿Alguien ha hecho la sobrecarga de constructores en TypeScript. En la página 64 de la especificación de lenguaje (v 0.8), hay declaraciones que describen sobrecargas de constructores, pero no se proporcionó ningún código de ejemplo.
Estoy probando una declaración de clase realmente 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 se ejecuta con tsc BoxSample.ts, arroja una definición de constructor duplicada, lo cual es obvio. Cualquier ayuda es apreciada.
Con respecto a las sobrecargas de constructores, una alternativa sería implementar las sobrecargas adicionales como métodos estáticos de fábrica . Creo que es más legible y menos confuso que probar tus argumentos de llamada. Aquí hay un ejemplo simple:
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 en TypeScript no es real , digamos, ya que requeriría demasiado código generado por compilador y el equipo central intentará evitarlo a toda costa. Actualmente, la razón principal por la que la sobrecarga de métodos está presente en el lenguaje es proporcionar una forma de escribir declaraciones para bibliotecas con argumentos mágicos en su API. Ya que tendrá que hacer todo el trabajo pesado para manejar diferentes conjuntos de argumentos, no veo mucha ventaja en el uso de sobrecargas en lugar de métodos separados.
Debes tener en cuenta que ...
contructor()
constructor(a:any, b:any, c:any)
Es lo mismo que new()
o new("a","b","c")
Así
constructor(a?:any, b?:any, c?:any)
es el mismo de arriba y es más flexible ...
new()
o new("a")
o new("a","b")
o new("a","b","c")
En el caso de que un parámetro opcional, escrito sea lo suficientemente bueno, considere el siguiente código que cumple lo mismo sin repetir las propiedades o definir 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 pasadas en la track
, incluso si no están definidas en la Track
.
Puede manejar esto por:
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) sean opcionales, permitiendo múltiples constructores
por ejemplo: puede hacer una new Box({x,y})
sin altura y ancho.
El = {}
manejará valores falsos como indefinido, nulo, etc., y luego puede hacer una new Box()
Sé que esta es una pregunta antigua, pero nueva en 1.4 es tipos de unión; Utilícelos para todas las sobrecargas de funciones (incluidos los constructores). Ejemplo:
class foo {
private _name: any;
constructor(name: string | number) {
this._name = name;
}
}
var f1 = new foo("bar");
var f2 = new foo(1);
Tenga en cuenta que también puede solucionar la falta de sobrecarga en el nivel de implementación a través de los parámetros predeterminados en TypeScript, 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;
}
}
Edición: a partir del 5 de diciembre de 2016, vea la respuesta de Benson para obtener una solución más elaborada que permita una mayor flexibilidad.
TypeScript le permite declarar sobrecargas pero solo puede tener una implementación y esa implementación debe tener una firma que sea compatible con todas las sobrecargas. En su 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;
}
}
Nota: esto se simplificó y actualizó el 4/13/2017 para reflejar TypeScript 2.1, vea la historia para la respuesta de TypeScript 1.8.
Parece que desea que el parámetro objeto sea opcional, y también que cada una de las propiedades en el objeto sea opcional. En el ejemplo, como se proporciona, la sintaxis de sobrecarga no es necesaria. Quería señalar algunas malas prácticas en algunas de las respuestas aquí. Por supuesto, no es la expresión más pequeña posible de un box = { x: 0, y: 87, width: 4, height: 0 }
escritura esencialmente box = { x: 0, y: 87, width: 4, height: 0 }
, pero esto proporciona todas las sutilezas de sugerencias de código que posiblemente desee 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 valores predeterminados.
/** @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;
// 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;
}
}
Esta es una forma muy segura de escribir para parámetros que pueden no tener todas las propiedades del objeto definido. Ahora puedes escribir con seguridad cualquiera de estos:
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 son verdaderamente opcionales, que evitan los inconvenientes de una sintaxis alternativa muy utilizada (pero propensa a errores) de var = isOptional || default;
var = isOptional || default;
marcando contra el void 0
, que es una abreviatura para 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;
}());
Anexo: Configuración de valores por defecto: de forma incorrecta
El ||
(o) operador
Considere el peligro de ||
/ u operadores al configurar los valores predeterminados de respaldo, como se muestra en algunas otras respuestas. Este código a continuación ilustra la forma incorrecta de establecer los valores predeterminados. Puede obtener resultados inesperados al evaluar valores falsey como 0, '''', nulo, 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 (este, obj)
En mis pruebas, el uso de es6 / typescript desestructurado objeto puede ser casi un 90% más rápido que Object.assign . El uso de un parámetro desestructurado solo 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 TypeScript e intentó colocar un parámetro que no pertenecía, digamos, podrían intentar poner una propiedad 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 obj.
console.assert(typeof box.z === ''undefined'')
Actualización (8 de junio de 2017): guyarad y snolflake hacen puntos válidos en sus comentarios a continuación a mi respuesta. Recomendaría a los lectores que miren las respuestas de Benson , Joe y snolflake que tienen mejores respuestas que las mías.
Respuesta original (27 de enero de 2014)
Otro ejemplo de cómo lograr la sobrecarga de constructores:
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