¿Cómo hacer la sobrecarga de métodos en TypeScript?

9 minutos de lectura

avatar de usuario
Vacío-995

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 el truco 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);

¿Cómo hacer la sobrecarga de métodos en el lenguaje TypeScript?

  • @hakre Eso es algo extraño de decir, considerando que TypeScript ya admite la sobrecarga de métodos.

    – svick

    2 de octubre de 2012 a las 11:01

  • @svick: bueno, ¿a ese método le llamas sobrecarga? En su respuesta, el método en sí no está sobrecargado, un cuerpo está presente.

    – hakré

    2 de octubre de 2012 a las 11:14

  • @hakre La especificación lo llama sobrecarga de métodos. Ciertamente puedes argumentar que no es una versión particularmente agradable, pero creo que no puedes decir que no existe en absoluto.

    – svick

    2 oct 2012 a las 11:21

  • @svick: Yo tampoco dije. Pero me parece que las posibilidades sobre las que pregunta OP son específicas sobre el modelo mental de sobrecarga de métodos. Para la división de cabello, podríamos decir que es una sobrecarga de firma de método;)

    – hakré

    2 oct 2012 a las 11:23

  • ¿Responde esto a tu pregunta? Sobrecarga de la función TypeScript

    – Michael Freidgeim

    31 de mayo de 2020 a las 1:50

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 cerca que puede estar de la sobrecarga de métodos en JavaScript simple incluye esa verificación también y TypeScript intenta no modificar los cuerpos de los métodos reales para evitar cualquier costo de rendimiento de tiempo de ejecución innecesario.

Si lo entiendo correctamente, primero debe escribir una declaración de método para cada una de las sobrecargas y luego una implementación del método que verifica sus argumentos para decidir qué sobrecarga se llamó. La firma de la implementación tiene que 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);
    }
}

  • @NicoVanBelle JavaScript no admite la sobrecarga de métodos, ¿verdad? Entonces, ¿cómo va a ayudar volver a JS?

    – svick

    11 de septiembre de 2017 a las 9:26

  • ¿Qué pasa con la comprobación de las interfaces? ¿Tiene una solución mejor que esa: stackoverflow.com/questions/14425568/… ?

    – DiPix

    28 de marzo de 2018 a las 10:19


  • hmm.. realmente no me gusta esto, solo tener un parámetro opcional en su lugar es mejor para leer.

    – LuckyLikey

    13 de noviembre de 2018 a las 15:22

  • Creo que lo importante aquí es que mantiene su código legible sin una tonelada de verificación de tipo si declaraciones. A quién le importa en qué se transpila.

    – Cerebro2000

    15 de junio de 2019 a las 23:07

avatar de usuario
Fenton

Actualizar 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 tipo para bibliotecas existentes con una API que necesita ser representada.

Sin embargo, al escribir su propio código, 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 pedidos poco intuitivos.

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

Por lo general, 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 lenguajes que admiten sobrecargas con implementaciones separadas (nota: las sobrecargas de TypeScript comparten una sola implementación), los programadores son consejos para brindar coherencia en el pedido. Esto haría que las firmas:

someMethod(stringParameter: string): void {

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

los stringParameter siempre es obligatorio, por lo que va primero. Podría 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 sobrecargas de TypeScript, podemos eliminar las firmas de sobrecarga y todas nuestras pruebas aún pasarán.

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

La pregunta real, en el orden real

Si estuviera decidido a persistir con el pedido 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;
    }
  }
}

Eso es mucha bifurcación para determinar dónde poner los parámetros, pero realmente quería conservar este orden si está leyendo hasta aquí… pero espere, ¿qué sucede si aplicamos la ley de sobrecargas de 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;
    }
  }
}

Suficiente ramificación ya

Por supuesto, dada la cantidad de verificación de tipos que necesitamos hacer… tal vez la mejor respuesta sea simplemente tener dos métodos:

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

someOtherMethod(numberParameter: number, stringParameter: string): void {
  //...
}

  • que comúnmente no se conoce como sobrecarga de métodos. también vea la pregunta, el tipo del primer parámetro cambia.

    – hakré

    2 oct 2012 a las 10:49

  • Reconocí eso en mi respuesta: pondría el parámetro opcional en último lugar, por lo que el number el parámetro sería el segundo argumento y sería opcional. TypeScript no admite sobrecargas de métodos “adecuados”, pero incluso el mundo de C# se está alejando de las sobrecargas hacia parámetros opcionales, ya que en muchos casos conduce a un código más legible.

    – Fenton

    2 oct 2012 a las 14:02


  • Te refieres a if (typeof numberParameter != 'undefined')Correcto 😉

    – Juan Mendes

    28 de octubre de 2016 a las 5:25

  • Eso depende de su caso de uso, en particular si acepta ceros. Si necesita hacerlo, recuerde usar !== para evitar malabarismos.

    – Fenton

    31/10/2016 a las 12:52

  • @Sebastian eso suena como una oportunidad para la inyección de dependencia. Dado que la sobrecarga de métodos en TypeScript implica un solo método con múltiples decoraciones, parámetros predeterminados y tipos de unión, proporcione una mejor experiencia. Si los métodos difieren en formas más sustanciales, usa una abstracción o implementa múltiples métodos.

    – Fenton

    6 de diciembre de 2017 a las 13:34

avatar de usuario
nicopoliptico

Deseo. También quiero esta función, pero TypeScript debe ser interoperable con JavaScript sin tipo que no tenga métodos sobrecargados. es decir, si su método sobrecargado se llama desde JavaScript, solo se puede enviar a una implementación de método.

Hay algunas discusiones relevantes sobre codeplex. p.ej

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

Sigo pensando que TypeScript debería generar todo el if’ing y el cambio para que no tengamos que hacerlo.

porque no usar interfaz opcional definida por propiedades como el argumento de la función..

Para el caso de esta pregunta, el uso de una interfaz en línea definida con algunas propiedades opcionales solo podría crear directamente un código como el siguiente:

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

Debido a que la sobrecarga provista en TypeScript es, como se menciona en los comentarios de otros, solo una lista de las diferentes firmas de funciones sin admitir los códigos de implementación correspondientes como otros lenguajes estáticos. Por lo tanto, la implementación aún debe realizarse 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 admiten la función de sobrecarga real.

Sin embargo, todavía hay muchas cosas nuevas y convenientes proporcionadas en mecanografiado que no están disponibles en el lenguaje de programación heredado, donde el soporte de propiedad opcional en una interfaz anónima es un enfoque tal para encontrar la zona cómoda de la sobrecarga de funciones heredadas, creo.

Si hay muchas variaciones de sobrecargas de métodos, otra forma es simplemente crear una clase con todos sus argumentos dentro. Entonces puede pasar solo el parámetro que desee en cualquier orden.

class SomeMethodConfig {
  stringParameter: string;
  numberParameter: number;

 /**
 *
 */
 constructor(stringParameter: string = '012', numberParameter?: number) { // different ways to make a param optional
   this.numberParameter = 456; // you can put a default value here
   this.stringParameter = stringParameter; // to pass a value throw the constructor if necessary
 }
}

También puede crear un constructor con valores predeterminados y/o pasar algunos argumentos obligatorios. Entonces solo usa así:

const config = new SomeMethodConfig('text');
config.numberParameter = 123; // initialize an optional parameter only if you want to do it
this.SomeMethod(config);

¿Ha sido útil esta solución?

Esta web utiliza cookies propias y de terceros para su correcto funcionamiento y para fines analíticos y para mostrarte publicidad relacionada con sus preferencias en base a un perfil elaborado a partir de tus hábitos de navegación. Al hacer clic en el botón Aceptar, acepta el uso de estas tecnologías y el procesamiento de tus datos para estos propósitos. Configurar y más información
Privacidad