Чи є спосіб зробити перевантаження методу в TypeScript?


109

Чи є спосіб зробити перевантаження методу мовою TypeScript?

Я хочу досягти чогось такого:

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

Ось приклад того, що я не хочу робити (я дуже ненавиджу цю частину перевантаження хака в 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);

1
Так, є шанс, мова ще не вмерла. Є ще запитання?
хакре

6
@hakre Це дивно сказати, враховуючи, що TypeScript вже підтримує метод перевантаження.
svick

@svick: ну ти називаєш цей метод перевантаженням? У вашій відповіді сам метод не перевантажений, одне тіло, якщо навколо.
хакре

2
@hakre Специфікація називає це метод перевантаження. Ви, звичайно, можете стверджувати, що це не особливо приємна версія його, але я думаю, ви не можете сказати, що вона взагалі не існує.
svick

@svick: Я теж не сказав. Але мені здається, що шанси, про які задає ОП, є специфічними щодо ментальної моделі перевантаження методом. Для роздвоєння волосся можна сказати, що це метод перевантаження підписів;)
hakre

Відповіді:


165

Відповідно до специфікації, TypeScript робить метод перевантаження перегрузкою, але це досить незручно і включає безліч ручних робіт, перевіряючи типи параметрів. Я думаю, що це здебільшого тому, що найближчим чином ви можете дістатись до перевантаження методу в простому JavaScript, що включає перевірку і TypeScript намагається не змінювати фактичні органи методів, щоб уникнути зайвих витрат на виконання часу.

Якщо я правильно це розумію, потрібно спершу написати декларацію методу для кожної з перевантажень, а потім одну реалізацію методу, яка перевіряє його аргументи, щоб вирішити, яка перевантаження викликалася. Підпис реалізації повинен бути сумісним з усіма перевантаженнями.

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

3
@NicoVanBelle JavaScript взагалі не підтримує метод перевантаження, правда? Отже, як повернутися до JS, щоб допомогти?
svick

Що щодо перевірки інтерфейсів? Чи маєте ви краще рішення: stackoverflow.com/questions/14425568/… ?
DiPix

хм .. мені це дуже не подобається, просто маючи додатковий параметр замість цього краще читати.
LuckyLikey

3
Я думаю, що тут важливо, це те, що він зберігає ваш код читабельний без тони перевірки тексту, якщо заяви. Кому байдуже, у що це перетворюється.
Brain2000

34

Оновлення для наочності. Перевантаження методу в TypeScript - корисна функція, оскільки дозволяє створювати визначення типів для існуючих бібліотек з API, який потрібно представити.

При написанні власного коду, можливо, ви зможете уникнути когнітивних накладних перевантажень, використовуючи додаткові параметри або параметри за замовчуванням. Це більш читана альтернатива методу перевантажень, а також зберігає ваш API чесним, оскільки ви уникнете створення перевантажень при неінтуїтивному впорядкуванні.

Загальний закон перевантаження TypeScript:

Якщо ви можете видалити підписи перевантаження і всі ваші тести пройдуть, вам не потрібні перевантаження TypeScript

Зазвичай ви можете домогтися того ж, використовуючи необов’язкові параметри або параметри за замовчуванням - або з типами об'єднання, або з трохи орієнтацією на об'єкт.

Актуальне питання

Справжнє запитання вимагає перевантаження:

someMethod(stringParameter: string): void {

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

Тепер навіть у мовах, які підтримують перевантаження з окремими реалізаціями (зауважте: TypeScript перевантаження розділяють одну реалізацію) - програмісти - це поради, які забезпечують послідовність у замовленні. Це зробить підписи:

someMethod(stringParameter: string): void {

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

Це stringParameterзавжди потрібно, тому воно йде спочатку. Ви можете написати це як робоче перевантаження 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...
    }
}

Але, дотримуючись закону TypeScript про перевантаження, ми можемо видалити підписи перевантаження і всі наші тести все одно пройдуть.

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

Актуальне питання, у фактичному порядку

Якщо ви вирішили зберегти оригінальне замовлення, перевантаження будуть:

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

Тепер це дуже багато розгалужень, щоб розібратися, де розмістити параметри, але ви дуже хотіли зберегти цей порядок, якщо читаєте це далеко ... але зачекайте, що станеться, якщо ми застосуємо закон перевантаження 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;
    }
  }
}

Досить вже розгалуження

Звичайно, враховуючи кількість перевірки типу, що нам потрібно зробити ... можливо, найкраща відповідь - це просто два способи:

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

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

що зазвичай не відомий як метод перевантаження. також дивіться питання, змінюється тип першого параметра.
хакре

3
Я визнав, що у своїй відповіді - ви поставите необов’язковий параметр останнім, тож numberпараметр буде другим аргументом і буде необов’язковим. TypeScript не підтримує "належний" метод перевантаження - але навіть світ C # відходить від перевантажень до необов'язкових параметрів, оскільки в багатьох випадках це призводить до більш читабельного коду.
Фентон

Ви маєте на увазі if (typeof numberParameter != 'undefined'), так;)
Хуан Мендес

Це залежить від вашого випадку використання, зокрема від того, чи приймаєте ви нулі. Якщо вам потрібно це зробити, не забудьте використовувати, !==щоб уникнути жонглювання.
Фентон

1
@Sebastian, що звучить як можливість для введення залежності. Зважаючи на те, що перевантаження методу в TypeScript передбачає єдиний метод з декількома декорами, параметрами за замовчуванням та типами об'єднання, що забезпечують кращий досвід. Якщо методи відрізняються більш істотними способами, ви або використовуєте абстракцію, або застосовуєте кілька методів.
Фентон

7

Бажаю. Я також хочу цю функцію, але TypeScript повинен бути сумісний з типовим JavaScript, який не має перевантажених методів. тобто, якщо ваш перевантажений метод викликається з JavaScript, він може бути відправлений лише до одного способу реалізації.

Є мало відповідних дискусій щодо кодеплексу. напр

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

Я все ще думаю, що TypeScript повинен генерувати все if'ing та перемикання, щоб нам не потрібно було це робити.


2

Чому б не використовувати додатковий інтерфейс, визначений властивістю як аргумент функції.

У випадку з цим питанням використання вбудованого інтерфейсу, визначеного лише деякими необов'язковими властивостями, може безпосередньо зробити код, як-то нижче:

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

Оскільки перевантаження, що надається в TypeScript, - це, як згадується в коментарях інших, лише список різних підписів функції без підтримки відповідних кодів реалізації, як інші статичні мови. Тому реалізацію все-таки потрібно проводити лише в одному функціональному органі, що робить перевантаження функцій в Typescript не таким зручним, як такі мови, що підтримують функцію реальної перевантаження.

Однак, є ще багато нових та зручних матеріалів, що надаються в машинописі, який недоступний у застарілій мові програмування, де опціональна підтримка властивостей в анонімному інтерфейсі - це такий підхід для задоволення зручної зони від перевантаженої застарілої функції.


0

Якщо існує велика кількість варіацій перевантажень методу, інший спосіб - просто створити клас із усіма вашими аргументами всередині. Таким чином, ви можете передавати лише потрібний параметр у будь-якому порядку.

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

Також ви можете створити конструктор зі значеннями за замовчуванням та / або передати деякі обов'язкові аргументи. Тоді просто використовуйте так:

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

-2

У JavaScript не існує жодної концепції перевантаження. Набір тексту не є c # або Java.

Але ви можете реалізувати перевантаження в Typescript.

Прочитайте цю публікацію http://www.gyanparkash.in/function-overloading-in-typescript/


На жаль, посилання розірвано. Ви можете репостувати?
LHM

@LMH: Ось чому відповіді, що стосуються лише посилань, не враховують.
Дан Даскалеску
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.