Có cách nào để thực hiện nạp chồng phương thức trong TypeScript không?


109

Có cách nào để thực hiện nạp chồng phương thức trong ngôn ngữ TypeScript không?

Tôi muốn đạt được điều gì đó như thế này:

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

Đây là một ví dụ về những gì tôi không muốn làm (tôi thực sự ghét phần hack quá tải trong 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
Vâng, có cơ hội, ngôn ngữ chưa chết. Còn câu hỏi nào nữa không?
hakre

6
@hakre Đó là một điều kỳ lạ để nói, vì TypeScript đã hỗ trợ nạp chồng phương thức.
svick

@svick: à, bạn có gọi phương thức đó là quá tải không? Trong câu trả lời của bạn, bản thân phương thức không bị quá tải, một phần nội dung nếu đang ở xung quanh.
hakre

2
@hakre Đặc tả gọi nó là quá tải phương thức. Bạn chắc chắn có thể tranh luận rằng nó không phải là một phiên bản đặc biệt hay của nó, nhưng tôi nghĩ bạn không thể nói rằng nó hoàn toàn không tồn tại.
svick

@svick: Tôi cũng không nói. Nhưng đối với tôi, cơ hội OP hỏi là cụ thể về mô hình tinh thần của quá trình nạp phương thức. Đối với tóc chẻ chúng ta có thể nói nó quá tải phương pháp chữ ký;)
hakre

Câu trả lời:


165

Theo đặc điểm kỹ thuật, TypeScript hỗ trợ nạp chồng phương thức, nhưng nó khá khó xử và bao gồm rất nhiều loại tham số kiểm tra công việc thủ công. Tôi nghĩ chủ yếu là do cách gần nhất bạn có thể tiếp cận với quá trình nạp chồng phương thức trong JavaScript thuần túy cũng bao gồm việc kiểm tra và TypeScript cố gắng không sửa đổi các phần thân phương thức thực tế để tránh mọi chi phí hiệu suất thời gian chạy không cần thiết.

Nếu tôi hiểu nó một cách chính xác, trước tiên bạn phải viết một khai báo phương thức cho mỗi lần quá tải và sau đó thực hiện một phương thức kiểm tra các đối số của nó để quyết định quá tải nào được gọi. Chữ ký của việc triển khai phải tương thích với tất cả các quá tải.

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 hoàn toàn không hỗ trợ nạp chồng phương thức, phải không? Vậy quay lại JS sẽ giúp ích như thế nào?
svick

Điều gì về việc kiểm tra các giao diện? Bạn có giải pháp tốt hơn không: stackoverflow.com/questions/14425568/… ?
DiPix

hmm .. tôi không thực sự thích điều này, thay vào đó, chỉ có một tham số tùy chọn sẽ tốt hơn để đọc.
LuckyLikey

3
Tôi nghĩ điều quan trọng ở đây là nó giữ cho mã của bạn có thể đọc được mà không cần phải đánh máy nhiều câu lệnh if. Ai quan tâm nó chuyển thành cái gì.
Brain2000

34

Cập nhật cho rõ ràng. Nạp chồng phương thức trong TypeScript là một tính năng hữu ích vì nó cho phép bạn tạo các định nghĩa kiểu cho các thư viện hiện có với một API cần được đại diện.

Tuy nhiên, khi viết mã của riêng bạn, bạn có thể tránh được tình trạng quá tải về chi phí nhận thức bằng cách sử dụng các tham số tùy chọn hoặc mặc định. Đây là giải pháp thay thế dễ đọc hơn cho quá tải phương thức và cũng giữ cho API của bạn trung thực vì bạn sẽ tránh tạo quá tải với thứ tự không trực quan.

Luật chung của quá tải TypeScript là:

Nếu bạn có thể xóa các chữ ký quá tải và tất cả các bài kiểm tra của bạn đều vượt qua, bạn không cần quá tải TypeScript

Bạn thường có thể đạt được điều tương tự với các tham số tùy chọn hoặc mặc định - hoặc với các kiểu liên hợp hoặc với một chút hướng đối tượng.

Câu hỏi thực tế

Câu hỏi thực tế yêu cầu quá tải:

someMethod(stringParameter: string): void {

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

Bây giờ, ngay cả trong các ngôn ngữ hỗ trợ quá tải với các triển khai riêng biệt (lưu ý: Quá tải TypeScript chia sẻ một triển khai duy nhất) - các lập trình viên được tư vấn để cung cấp tính nhất quán trong việc sắp xếp. Điều này sẽ làm cho các chữ ký:

someMethod(stringParameter: string): void {

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

Các stringParameterlà luôn luôn cần thiết, vì vậy nó đi đầu tiên. Bạn có thể viết điều này dưới dạng quá tải TypeScript đang hoạt động:

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

Nhưng tuân theo luật quá tải của TypeScript, chúng ta có thể xóa các chữ ký quá tải và tất cả các bài kiểm tra của chúng ta sẽ vẫn vượt qua.

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

Câu hỏi thực tế, theo thứ tự thực tế

Nếu bạn quyết tâm tiếp tục với đơn hàng ban đầu, quá tải sẽ là:

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

Bây giờ có rất nhiều nhánh để tìm ra nơi đặt các tham số, nhưng bạn thực sự muốn duy trì thứ tự này nếu bạn đang đọc đến đây ... nhưng khoan đã, điều gì sẽ xảy ra nếu chúng ta áp dụng luật quá tải 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;
    }
  }
}

Đã đủ phân nhánh

Tất nhiên, với số lượng kiểm tra kiểu mà chúng ta cần thực hiện ... có lẽ câu trả lời tốt nhất chỉ đơn giản là có hai phương pháp:

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

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

điều đó thường không được gọi là quá tải phương thức. cũng xem câu hỏi, loại của tham số đầu tiên thay đổi.
hakre

3
Tôi thừa nhận điều đó trong câu trả lời của mình - bạn sẽ đặt tham số tùy chọn cuối cùng, vì vậy numbertham số sẽ là đối số thứ hai và sẽ là tùy chọn. TypeScript không hỗ trợ quá tải phương thức "thích hợp" - nhưng ngay cả thế giới C # cũng đang chuyển từ trạng thái quá tải sang các tham số tùy chọn vì trong nhiều trường hợp, nó dẫn đến mã dễ đọc hơn.
Fenton

Ý bạn là if (typeof numberParameter != 'undefined'), đúng;)
Juan Mendes.

Điều đó phụ thuộc vào trường hợp sử dụng của bạn, cụ thể là bạn có chấp nhận các số 0 hay không. Nếu cần thực hiện, bạn nhớ sử dụng !==để tránh bị tung hứng.
Fenton,

1
@Sebastian, nghe có vẻ như một cơ hội để tiêm phụ thuộc. Cho rằng việc nạp chồng phương thức trong TypeScript liên quan đến một phương thức duy nhất với nhiều trang trí, tham số mặc định và kiểu liên hợp, mang lại trải nghiệm tốt hơn. Nếu các phương pháp khác nhau theo nhiều cách đáng kể, bạn có thể sử dụng một phần trừu tượng hoặc triển khai nhiều phương thức.
Fenton

7

Tôi ước. Tôi cũng muốn tính năng này nhưng TypeScript cần phải tương thích với JavaScript không định kiểu không có các phương thức quá tải. tức là Nếu phương thức được nạp chồng của bạn được gọi từ JavaScript thì nó chỉ có thể được gửi đến một phương thức triển khai.

Có một vài cuộc thảo luận có liên quan về codeplex. ví dụ

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

Tôi vẫn nghĩ rằng TypeScript nên tạo ra tất cả if'ing và chuyển đổi để chúng ta không cần phải làm điều đó.


2

Tại sao không sử dụng giao diện được xác định thuộc tính tùy chọn làm đối số hàm ..

Đối với trường hợp trong câu hỏi này, việc sử dụng giao diện nội tuyến được xác định với một số thuộc tính tùy chọn chỉ có thể trực tiếp tạo mã như một cái gì đó dưới đây:

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

Vì quá tải được cung cấp trong TypeScript, như đã đề cập trong nhận xét của những người khác, chỉ là danh sách các chữ ký khác nhau của hàm mà không hỗ trợ các mã triển khai tương ứng như các ngôn ngữ tĩnh khác. Vì vậy, việc triển khai vẫn phải được thực hiện chỉ trong một thân hàm, điều này làm cho việc sử dụng tính năng nạp chồng hàm trong Typescript không thoải mái như các ngôn ngữ hỗ trợ tính năng nạp chồng thực.

Tuy nhiên, vẫn còn nhiều thứ mới và tiện lợi được cung cấp trong bảng chữ mà không có sẵn trong ngôn ngữ lập trình kế thừa, trong đó hỗ trợ thuộc tính tùy chọn trong giao diện ẩn danh là một cách tiếp cận để đáp ứng vùng thoải mái khỏi quá tải hàm cũ, tôi nghĩ.


0

Nếu có nhiều biến thể của quá tải phương thức, một cách khác là tạo một lớp với tất cả các args của bạn bên trong. Vì vậy, bạn chỉ có thể chuyển tham số bạn muốn theo bất kỳ thứ tự nào.

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

Ngoài ra, bạn có thể tạo một hàm tạo với các giá trị mặc định và / hoặc chuyển một số đối số bắt buộc. Sau đó, chỉ cần sử dụng như thế này:

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

-2

Javascript không có bất kỳ khái niệm nào về quá tải. Typecript không phải là c # hoặc Java.

Nhưng bạn có thể thực hiện quá tải trong Typecript.

Đọc bài đăng này http://www.gyanparkash.in/ Chức năng-overloading-in-typescript/


Thật không may, liên kết bị hỏng. Bạn có thể đăng lại?
LHM

@LMH: Đó là lý do tại sao các câu trả lời chỉ có liên kết không được khuyến khích.
Dan Dascalescu
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.