betacode

Методы в TypeScript

  1. Что это за метод?
  2. Регулярный метод
  3. Статический метод
  4. Абстрактный метод
  5. опциональные параметры
  6. Параметры со значениями по умолчанию
  7. Параметры с типом данных объединения
  8. Переопределение метода
  9. Method Overloading

1. Что это за метод?

В языке программирования TypeScript метод представляет собой блок кода (block of code), определенный внутри класса и выполняемый только при вызове. Методы разделяют большую задачу на мелкие части и выполняют конкретную операцию этой программы. Этот процесс повышает возможность повторного использования кода и расширяет модульный подход программы.
В основном методы делятся на 3 типа:
  • Регулярный метод (нестатический и неабстрактный).
  • Статический метод (static method).
  • Абстрактный метод (abstract method).

2. Регулярный метод

Синтаксис для определения регулярного метода:
[private | protected | public] method_name(arguments) : return_type {  
     // statement(s)  
}
  • return_type: Возвращаемый тип данных метода. Используйте ключевое слово void в качестве типа возвращаемого значения, если метод ничего не возвращает.
  • method_name:Имя метода. В отличие от других языков, таких как Java, TypeScript не допускает двух методов с одинаковым именем, даже если они имеют разные параметры. Это необходимо для преобразования кода TypeScript в Javascript.
  • arguments: Параметры метода.
Например: класс Cat и метод sayHello(..). Чтобы вызвать sayHello(..), необходимо создать объект Cat и вызвать метод, используя точечную нотацию (dot notation).
method_ex1.ts
class Cat {
    sayHello(name: string): void {
        console.log(`Hello ${name}`);
    }
}
function method_ex1_test() {
    var tom: Cat = new Cat(); // Create a Cat object.
    tom.sayHello("Jerry"); // Call the method through the object.
}
// Call the method:
method_ex1_test();
Output:
Hello Jerry
Метод может содержать 0, 1 или более параметров, разделенных запятыми.
method_ex2.ts
class Rectangle {
    width: number;
    height: number;

    constructor(width: number, height: number) {
        this.width = width;
        this.height = height;
    }
    getArea(): number {
        return this.width * this.height;
    }
    changeWidthHeight(newWidth: number, newHeight: number): void {
        this.width = newWidth;
        this.height = newHeight;
    }
    showMe(): void {
        console.log(`I am a rectangle, width: ${this.width}, height: ${this.height}`);
    }
}
function method_ex2_test() {
    var rec = new Rectangle(5, 10); // Create an object.

    rec.showMe();  // Call the method.
    var area = rec.getArea();  // Call the method.
    console.log(`Area: ${area}`);

    console.log(` --- Change width and height --- `);
    rec.changeWidthHeight(25, 15); // Set newWidth, newHeight

    rec.showMe(); // Call the method.  
    area = rec.getArea(); // Call the method.
    console.log(`Area: ${area}`);
}
method_ex2_test(); // Call the function.
Output:
I am a rectangle, width: 5, height: 10
Area: 50
 --- Change width and height ---
I am a rectangle, width: 25, height: 15
Area: 375

3. Статический метод

TypeScript использует ключевое слово static в сочетании с синтаксисом определения обычного метода для определения статического метода.
Синтаксис:
[private | protected | public] static method_name(arguments) : return_type {  
     // statement(s)  
}
Характеристики статических методов:
  • Статический метод вызывается с помощью имени класса и точечной нотации. Например, MyUtility.sum(100, 50).
  • Нестатические члены класса не могут отображаться в статическом методе, если к ним не осуществляется доступ через объект (см. Пример ниже).
method_static_ex1.ts
class MyUtility {
    static sum(a: number, b: number): number { // same as 'public'
        return a + b;
    }
    public static minus(a: number, b: number): number {
        return a - b;
    }
}
function method_static_ex1_test() {
    var result = MyUtility.sum(100, 50);
    console.log(`Sum Result: ${result}`);

    result = MyUtility.minus(100, 50);
    console.log(`Minus Result: ${result}`);
}
method_static_ex1_test(); // Call the method
Output:
Sum Result: 150
Minus Result: 50
Затем посмотрите на приведенный ниже пример:
  • side1, side2 и side3 являются нестатическими полями класса Triangle, они не могут отображаться в статическом методе.
method_static_ex2.ts
class Triangle {
    side1: number; side2: number; side3: number;// Non-static fields (Cann't use in static method)
    static DEFAULT_COLOR:string = 'blue'; // Static field (Can use in static method)

    constructor(s1: number, s2: number, s3: number) {
        var valid = Triangle.isValidSides(s1, s2, s3); // Check if all sides are valid.
        if (!valid) {
            throw new Error('Invalid Sides!'); // Throw an Error.
        }
        this.side1 = s1;
        this.side2 = s2;
        this.side3 = s3;
    }
    static isValidSides(s1: number, s2: number, s3: number): boolean {
        if (s1 < 0 || s2 < 0 || s3 < 0) {
            return false;
        }
        return s1 + s2 > s3 && s1 + s3 > s2 && s2 + s3 > s1;
    }
    isEquilateralTriangle(): boolean {
        return this.side1 == this.side2 && this.side2 == this.side3;
    }
}
function method_static_ex2_test() {
    var valid = Triangle.isValidSides(6, 8, 10);
    console.log(`Are sides 6, 8 and 10 valid to make a triangle? ${valid}`);

    var triangle = new Triangle(3.0, 4.0, 5.0);
    // Check if the triangle is equilateral triangle.
    var check = triangle.isEquilateralTriangle();
    console.log(`Is Equilateral Triangle? ${check}`);
}
method_static_ex2_test(); // Call the method.
Output:
Are sides 6, 8 and 10 valid to make a triangle? true
Is Equilateral Triangle? false

4. Абстрактный метод

На языке TypeScript абстрактный метод является нестатическим методом и не имеет содержимого.
[protected | public] abstract method_name(arguments) : return_type;
Класс, имеющий по крайней мере один абстрактный метод, должен быть объявлен абстрактным, и один из его подклассов должен переопределять (override) эти абстрактные методы и писать для них содержимое.
method_abstract_ex1.ts
abstract class Person {
    abstract sayHello(): void; // An abstract method.
}
class EnglishPerson extends Person {
    sayHello(): void {
        console.log("Hello");
    }
}
class RussianPerson extends Person {
    sayHello(): void {
        console.log("Привет");
    }
}
function method_abstract_ex1_test() {
    var enPerson = new EnglishPerson();
    enPerson.sayHello();

    var ruPerson = new RussianPerson();
    ruPerson.sayHello();
}
method_abstract_ex1_test(); // Call the function.
Output:
Hello
Привет
  • TypeScript Classes

5. опциональные параметры

Как упоминалось выше, классы в TypeScript и JavaScript не допускают методов с одинаковыми именами, но метод может включать опциональные параметры.
Синтаксис:
// Non-static method with optional arguments:
[private | protected | public] method_name(args, optional_args?): return_type {  
     // statement(s)  
}

// Static method with optional arguments:
[private | protected | public] static method_name(args, optional_args?) : return_type {  
     // statement(s)  
}

// Abstract method with optional arguments:
[protected | public] abstract method_name(args, optional_args?): return_type;
Например:
method_optional_args_ex1.js
class MyUtils {
    static concat(s1: string, s2: string, s3?: string): string {
        if (s3) {
            return s1 + s2 + s3;
        }
        return s1 + s2;
    }
    static sum(v1: number, v2: number, v3?: number, v4?: number): number {
        return v1 + v2 + (v3 ?? 0) + (v4 ?? 0);
    }
}
function method_optional_args_ex1_test() {
    var result1 = MyUtils.concat('One', 'Two');
    console.log(`result1: ${result1}`);

    var result2 = MyUtils.concat('One', 'Two', 'Three');
    console.log(`result2: ${result2}`);

    var value1 = MyUtils.sum(1, 2, 3, 4);
    console.log(`value1: ${value1}`);

    var value2 = MyUtils.sum(1, 2, 3);
    console.log(`value2: ${value2}`);

    var value3 = MyUtils.sum(1, 2);
    console.log(`value3: ${value3}`);
}
method_optional_args_ex1_test(); // Call the method.
Output:
result1: OneTwo
result2: OneTwoThree
value1: 10
value2: 6
value3: 3

6. Параметры со значениями по умолчанию

TypeScript поддерживает методы с параметрами по умолчанию, которые должны быть последними параметрами в списке параметров.
Синтаксис:
// Non-static method
[private | protected | public ] method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type3 = defaultValue3,
             arg4 : data_type4 = defaultValue4) : return_type {
    // statement(s)  
}
// Static method
[private | protected | public ] static method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type3 = defaultValue3,
             arg4 : data_type4 = defaultValue4) : return_type {
   // statement(s)  
}
// Abstract method
[protected | public ] abstract method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type3 = defaultValue3,
             arg4 : data_type4 = defaultValue4) : return_type;
Например:
method_default_value_args_ex1.ts
class SalesUtils {
    static applyDiscount(amount : number, discount: number = 0.05)  : number {
        return amount * (1 - discount);
    }
}
function method_default_value_args_ex1_test() {
    var value1 = SalesUtils.applyDiscount(1000);
    console.log(`value1 = ${value1}`);

    var value2 = SalesUtils.applyDiscount(1000, 0.5);
    console.log(`value2 = ${value2}`);
}
method_default_value_args_ex1_test(); // Call the method.
Output:
value1 = 950
value2 = 500

7. Параметры с типом данных объединения

Параметр в методе также может быть объявлен с типом данных объединения (union data type).
// Non-static method
[private | protected | public ] method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type31 | data_type32 | data_type3N, // Union Data Type
             arg4 : data_type4 = defaultValue4) : return_type {
    //  Statament(s)
}
// Static method
[private | protected | public ] static method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type31 | data_type32 | data_type3N, // Union Data Type
             arg4 : data_type4) : return_type {
    //  Statament(s)  
}
// Abstract method
[protected | public ] abstract method_name (
             arg1 : data_type1, arg2 : data_type2,
             arg3 : data_type31 | data_type32 | data_type3N, // Union Data Type
             arg4 : data_type4) : return_type;
Например:
method_union_type_args_ex1.ts
interface IStudent {
    studentId: number,
    studentName: string
}
interface IWorker {
    workerId: number,
    workerName: string
}
class AppUtils {
    static getName(person: IStudent | IWorker): string { // Union Type Arg
        var p = person as IStudent;
        if (p.studentName) {
            return p.studentName;
        }
        return (person as IWorker).workerName;
    }
}
function method_union_type_args_ex1_test() {
    var student = { studentId: 1, studentName: "Tom" };
    var worker = { workerId: 2, workerName: "Jerry" };

    var name1 = AppUtils.getName(student);
    var name2 = AppUtils.getName(worker);
    console.log(`name1: ${name1}`);
    console.log(`name2: ${name2}`);
}
method_union_type_args_ex1_test(); // Call the method.
Output:
name1: Tom
name2: Jerry

8. Переопределение метода

Подкласс может переопределять (override) метод родительского класса, если выполняются следующие условия:
  • Два метода должны иметь одинаковое имя и одинаковые параметры.
  • Тип возвращаемого значения двух методов должен быть одинаковым, или тип возвращаемого значения метода в подклассе должен быть подтипом типа возвращаемого значения метода в родительском классе.
Например:
  • Класс Mouse переопределяет (override) метод sayAnything() класса Animal.
method_override_ex1.ts
class Animal {
    sayAnything(): void {
        console.log('<Nothing>');
    }
}
class Mouse extends Animal {
    sayAnything(): void { // Override method of parent class.
        console.log('Hi Tom!');
    }
}
function method_override_ex1_test() {
    var animal = new Mouse();
    animal.sayAnything(); // Hi Tom!
}
method_override_ex1_test(); // Call the function.
Output:
Hi Tom!
Например: Вы также можете использовать ключевое слово super для вызова метода с тем же именем родительского класса.
method_override_ex2.ts
class BoldFormatter {
    formatText(text: string): string {
        return '<b>' + text + '</b>';
    }
}
class BoldItalicFormatter extends BoldFormatter {
    formatText(text: string): string { // Override method of parent class.
        var boldText = super.formatText(text); // Call super method.
        return '<i>' + boldText + '</i>';
    }
}
function method_override_ex2_test() {
    var formatter = new BoldItalicFormatter();
    var formattedText = formatter.formatText('Hello');
    console.log(formattedText);
}
method_override_ex2_test(); // Call the method.
Output:
<i><b>Hello</b></i>

9. Method Overloading

В статье о функциях в TypeScript я представил "Function Overloading" (Перегрузку функций). Метод рассматривается как функция класса, поэтому он также имеет аналогичную концепцию, которая называется "Method Overloading" (Перегрузка метода).
TypeScript не допускает двух методов с одинаковым именем в классе, даже если они имеют разные параметры. Method Overloading позволяет определить метод с различными типами параметров.
В TypeScript, Method Overloading выглядит иначе, чем в C++, Java или C#. Основная идея перегрузки (overload) для метода заключается в создании универсального метода, который проверяет, какой тип параметра был передан при вызове метода, а затем выполняет некоторую логику для соответствующего случая. Полезно добавить определения для метода, чтобы помочь другим программистам узнать, как его правильно использовать.
Синтаксис:
// Definition 1
[static] method_name(arg_11 : type_11, arg_1N : type_1N): return_type;
]// Definition 2
[static] method_name(arg_21 : type_21, arg_22 : type_22, arg_2M : type_2M) : return_type;
[static] method_name(... args : any[]) : return_type {
   // Method body.
}
Например:
method_overloading_ex1.ts
interface IDimension {
    width: number,
    height: number
}
class MathUtils {
    static getArea(dimension: IDimension): number; // Definition 1
    static getArea(width: number): number; // Definition 2
    static getArea(width: number, height: number): number; // Definition 3
    static getArea(...args: any[]): number {
        if (args.length == 1) {
            if (typeof args[0] == 'number') { // Use Definition 2
                return args[0] * args[0];
            } else { // Use Definition 1
                var dim = args[0] as IDimension;
                return dim.width * dim.height;
            }
        } else if (args.length == 2) {
            return args[0] * args[1];
        } else {
            throw new Error('Arguments Invalid!');
        }
    }
}
function method_overloading_ex1_test() {
    var area1 = MathUtils.getArea({ width: 10, height: 20 }); // 200
    var area2 = MathUtils.getArea(10); // 100
    var area3 = MathUtils.getArea(10, 15); // 150

    console.log(`area1: ${area1}`);
    console.log(`area2: ${area2}`);
    console.log(`area3: ${area3}`);
}
method_overloading_ex1_test(); // Call the function.
Output:
area1: 200
area2: 100
area3: 150