¿Hay alguna manera de hacer la sobrecarga de métodos en TypeScript?


¿Hay alguna manera de hacer la sobrecarga de métodos en el lenguaje TypeScript?

Quiero lograr algo como esto:

class TestClass {
    someMethod(stringParameter: string): void {
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    someMethod(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }
}

var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");

Aquí hay un ejemplo de lo que no quiero hacer (realmente odio esa parte de sobrecargar hack en JS):

class TestClass {
    private someMethod_Overload_string(stringParameter: string): void {
        // A lot of code could be here... I don't want to mix it with switch or if statement in general function
        alert("Variant #1: stringParameter = " + stringParameter);
    }

    private someMethod_Overload_number_string(numberParameter: number, stringParameter: string): void {
        alert("Variant #2: numberParameter = " + numberParameter + ", stringParameter = " + stringParameter);
    }

    private someMethod_Overload_string_number(stringParameter: string, numberParameter: number): void {
        alert("Variant #3: stringParameter = " + stringParameter + ", numberParameter = " + numberParameter);
    }

    public someMethod(stringParameter: string): void;
    public someMethod(numberParameter: number, stringParameter: string): void;
    public someMethod(stringParameter: string, numberParameter: number): void;

    public someMethod(): void {
        switch (arguments.length) {
        case 1:
            if(typeof arguments[0] == "string") {
                this.someMethod_Overload_string(arguments[0]);
                return;
            }
            return; // Unreachable area for this case, unnecessary return statement
        case 2:
            if ((typeof arguments[0] == "number") &&
                (typeof arguments[1] == "string")) {
                this.someMethod_Overload_number_string(arguments[0], arguments[1]);
            }
            else if ((typeof arguments[0] == "string") &&
                     (typeof arguments[1] == "number")) {
                this.someMethod_Overload_string_number(arguments[0], arguments[1]);
            }
            return; // Unreachable area for this case, unnecessary return statement
        }
    }
}


var testClass = new TestClass();
testClass.someMethod("string for v#1");
testClass.someMethod(12345, "string for v#2");
testClass.someMethod("string for v#3", 54321);
Author: Chris Williams, 2012-10-02

4 answers

De acuerdo con la especificación, TypeScript admite la sobrecarga de métodos, pero es bastante incómodo e incluye mucho trabajo manual para verificar tipos de parámetros. Creo que se debe principalmente a que lo más cercano que puede llegar a la sobrecarga de métodos en JavaScript plano incluye esa comprobación también y TypeScript intenta no modificar los cuerpos de los métodos reales para evitar cualquier costo innecesario de rendimiento en tiempo de ejecución.

Si lo entiendo correctamente, primero tiene que escribir una declaración de método para cada uno de las sobrecargas y luego una implementación del método que comprueba sus argumentos para decidir a qué sobrecarga se llamó. La firma de la implementación debe ser compatible con todas las sobrecargas.

class TestClass {
    someMethod(stringParameter: string): void;
    someMethod(numberParameter: number, stringParameter: string): void;

    someMethod(stringOrNumberParameter: any, stringParameter?: string): void {
        if (stringOrNumberParameter && typeof stringOrNumberParameter == "number")
            alert("Variant #2: numberParameter = " + stringOrNumberParameter + ", stringParameter = " + stringParameter);
        else
            alert("Variant #1: stringParameter = " + stringOrNumberParameter);
    }
}
 118
Author: svick,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2012-10-02 11:00:51

Actualización para mayor claridad. La sobrecarga de métodos en TypeScript es una característica útil en la medida en que le permite crear definiciones de tipos para bibliotecas existentes con una API que necesita ser representada.

Al escribir su propio código, sin embargo, es posible que pueda evitar la sobrecarga cognitiva de las sobrecargas utilizando parámetros opcionales o predeterminados. Esta es la alternativa más legible a las sobrecargas de métodos y también mantiene su API honesta, ya que evitará crear sobrecargas con poco intuitivo ordenar.

La ley general de las sobrecargas de TypeScript es:

Si puede eliminar las firmas de sobrecarga y todas sus pruebas pasan, no necesita sobrecargas de TypeScript

Normalmente se puede lograr lo mismo con parámetros opcionales o predeterminados, o con tipos de unión, o con un poco de orientación a objetos.

La Pregunta Real

La pregunta real pide una sobrecarga de:

someMethod(stringParameter: string): void {

someMethod(numberParameter: number, stringParameter: string): void {

Ahora, incluso en idiomas que admiten sobrecargas con implementaciones separadas (nota: las sobrecargas de TypeScript comparten una sola implementación) - los programadores son consejos para proporcionar consistencia en el orden. Esto haría que las firmas:

someMethod(stringParameter: string): void {

someMethod(stringParameter: string, numberParameter: number): void {

El stringParameter siempre es necesario, por lo que va primero. Puedes escribir esto como una sobrecarga de trabajo de TypeScript:

someMethod(stringParameter: string): void;
someMethod(stringParameter: string, numberParameter: number): void;
someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

Pero siguiendo la ley de las sobrecargas de TypeScript, podemos eliminar las firmas de sobrecarga y todas nuestras pruebas seguirán pasando.

someMethod(stringParameter: string, numberParameter?: number): void {
    if (numberParameter != null) {
        // The number parameter is present...
    }
}

La Pregunta Real, En el Orden real

Si estuviera determinado a persistir con el orden original, las sobrecargas serían:

someMethod(stringParameter: string): void;
someMethod(numberParameter: number, stringParameter: string): void;
someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

Ahora eso es un montón de ramificación para averiguar dónde poner los parámetros, pero realmente quería preservar este orden si está leyendo hasta aquí... pero espera, ¿qué pasa si aplicamos la ley de sobrecargas TypeScript?

someMethod(a: string | number, b?: string | number): void {
  let stringParameter: string;
  let numberParameter: number;

  if (typeof a === 'string') {
    stringParameter = a;
  } else {
    numberParameter = a;

    if (typeof b === 'string') {
      stringParameter = b;
    }
  }
}

Ya Basta de Ramificaciones

Por supuesto, dada la cantidad de comprobación de tipos que necesitamos hacer... tal vez la mejor respuesta es simplemente tener método dos:

someMethod(stringParameter: string): void {
  this.someOtherMethod(0, stringParameter);
}

someOtherMethod(numberParameter: number, stringParameter: string): void {
  //...
}
 20
Author: user75525,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-06 14:38:27

Ojalá. Quiero esta característica también, pero TypeScript necesita ser interoperable con JavaScript sin tipo que no tiene métodos sobrecargados. es decir, si su método sobrecargado se llama desde JavaScript, entonces solo se puede enviar a una implementación de método.

Hay algunas discusiones relevantes sobre codeplex. por ejemplo,

Https://typescript.codeplex.com/workitem/617

Sigo pensando que TypeScript debería generar todos los if'ing y switching para que no necesitemos haciéndolo.

 7
Author: nicopolyptic,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2013-07-20 20:07:32

Por qué no usar la propiedad opcional interfaz definida como argumento de la función..

Para el caso de esta pregunta, usar una interfaz en línea definida con algunas propiedades opcionales solo podría hacer directamente código como algo a continuación:

class TestClass {

    someMethod(arg: { stringParameter: string, numberParameter?: number }): void {
        let numberParameterMsg = "Variant #1:";
        if (arg.numberParameter) {
            numberParameterMsg = `Variant #2: numberParameter = ${arg.numberParameter},`;
        }
        alert(`${numberParameterMsg} stringParameter = ${arg.stringParameter}`);
    }
}

var testClass = new TestClass();
testClass.someMethod({ stringParameter: "string for v#1" });
testClass.someMethod({ numberParameter: 12345, stringParameter: "string for v#2" });

Porque la sobrecarga proporcionada en TypeScript es, como se menciona en los comentarios de otros, solo una lista de las diferentes firmas de la función sin soportar los códigos de implementación correspondientes como otros lenguajes estáticos. Así que el la implementación todavía tiene que hacerse en un solo cuerpo de función, lo que hace que el uso de la sobrecarga de funciones en Typescript no sea tan cómodo como los lenguajes que soportan la característica de sobrecarga real.

Sin embargo, todavía hay muchas cosas nuevas y convenientes proporcionadas en typescript que no están disponibles en el lenguaje de programación heredado, donde el soporte de propiedades opcional en una interfaz anónima es un enfoque para cumplir con la zona cómoda de la sobrecarga de la función heredada, I pensar.

 1
Author: 千木郷,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/ajaxhispano.com/template/agent.layouts/content.php on line 61
2017-12-10 15:12:02