2013-02-01 29 views
292

Trong TypeScript, tôi có thể khai báo một tham số của một hàm như một kiểu Hàm. Có một cách "an toàn" loại này mà tôi đang thiếu? Ví dụ, hãy xem xét điều này:Các hàm được đánh mạnh có phải là các tham số có thể có trong TypeScript không?

class Foo { 
    save(callback: Function) : void { 
     //Do the save 
     var result : number = 42; //We get a number from the save operation 
     //Can I at compile-time ensure the callback accepts a single parameter of type number somehow? 
     callback(result); 
    } 
} 

var foo = new Foo(); 
var callback = (result: string) : void => { 
    alert(result); 
} 
foo.save(callback); 

Các lưu callback không phải là loại an toàn, tôi cho nó một chức năng gọi lại nơi tham số của hàm là một chuỗi nhưng tôi đi qua nó một con số, và biên dịch không có lỗi. Tôi có thể làm cho tham số kết quả trong việc lưu một chức năng loại an toàn không?

phiên bản tl; dr: có tương đương với ủy quyền .NET trong TypeScript không?

Trả lời

427

chắc:

class Foo { 
    save(callback: (n: number) => any) : void { 
     callback(42); 
    } 
} 
var foo = new Foo(); 

var strCallback = (result: string) : void => { 
    alert(result); 
} 
var numCallback = (result: number) : void => { 
    alert(result.toString()); 
} 

foo.save(strCallback); // not OK 
foo.save(numCallback); // OK 

Nếu bạn muốn, bạn có thể xác định một loại để đóng gói này:

type NumberCallback = (n: number) => any; 

class Foo { 
    // Equivalent 
    save(callback: NumberCallback) : void { 
     callback(42); 
    } 
} 
+1

Huh, điều đó có vẻ hiển nhiên bây giờ. Cảm ơn! – vcsjones

+4

'' '(n: number) => any''' có nghĩa là bất kỳ chữ ký hàm nào không? –

+7

@nikkwong nghĩa là hàm lấy một tham số (một 'số') nhưng kiểu trả về không bị giới hạn (có thể là bất kỳ giá trị nào hoặc thậm chí là' void') –

62

Dưới đây là tương đương nguyên cảo của một số đại biểu NET chung:

interface Action<T> 
{ 
    (item: T): void; 
} 

interface Func<T,TResult> 
{ 
    (item: T): TResult; 
} 
+0

Có thể hữu ích để xem xét nhưng nó sẽ là một mô hình chống thực sự sử dụng các loại như vậy. Dù sao những cái nhìn giống như Java SAM loại hơn C# đại biểu.Tất nhiên họ không và chúng tương đương với hình thức bí danh loại mà chỉ là thanh lịch hơn cho các chức năng –

+3

@AluanHaddad bạn có thể giải thích về lý do tại sao bạn sẽ nghĩ rằng đây là một mô hình chống ? –

+3

Lý do là TypeScript có cú pháp chữ loại hàm ngắn gọn làm giảm bớt sự cần thiết cho các giao diện như vậy. Trong các đại biểu C# là danh nghĩa, nhưng các đại biểu 'Action' và' Func' đều làm giảm hầu hết nhu cầu đối với các loại đại biểu cụ thể và, thú vị, hãy cho C# một ngữ nghĩa của việc gõ cấu trúc. Nhược điểm của các đại biểu này là tên của họ không có ý nghĩa gì nhưng những lợi thế khác thường lớn hơn điều này. Trong TypeScript, chúng ta không cần những kiểu này. Vì vậy, các mô hình chống sẽ là 'bản đồ chức năng (xs: T [], f: Func )'. Ưu tiên 'bản đồ chức năng (xs: T [], f: (x: T) => U)' –

6

Tôi nhận thấy bài đăng này cũ, nhưng có một cách tiếp cận nhỏ gọn hơn hơi khác so với những gì được hỏi, bu t có thể là một lựa chọn rất hữu ích. Về cơ bản, bạn có thể khai báo chức năng trực tuyến khi gọi phương thức ('s save() trong trường hợp này). Nó sẽ trông giống như sau:

class Foo { 
    save(callback: (n: number) => any) : void { 
     callback(42) 
    } 

    multipleCallbacks(firstCallback: (s: string) => void, secondCallback: (b: boolean) => boolean): void { 
     firstCallback("hello world") 

     let result: boolean = secondCallback(true) 
     console.log("Resulting boolean: " + result) 
    } 
} 

var foo = new Foo() 

// Single callback example. 
// Just like with @RyanCavanaugh's approach, ensure the parameter(s) and return 
// types match the declared types above in the `save()` method definition. 
foo.save((newNumber: number) => { 
    console.log("Some number: " + newNumber) 

    // This is optional, since "any" is the declared return type. 
    return newNumber 
}) 

// Multiple callbacks example. 
// Each call is on a separate line for clarity. 
// Note that `firstCallback()` has a void return type, while the second is boolean. 
foo.multipleCallbacks(
    (s: string) => { 
     console.log("Some string: " + s) 
    }, 
    (b: boolean) => { 
     console.log("Some boolean: " + b) 
     let result = b && false 

     return result 
    } 
) 

Cách tiếp cận multipleCallback() rất hữu ích cho những thứ như cuộc gọi mạng có thể thành công hay thất bại. Một lần nữa giả sử một ví dụ về cuộc gọi mạng, khi gọi là multipleCallbacks(), hành vi cho cả thành công lẫn thất bại có thể được xác định tại một điểm, điều này cho phép rõ ràng hơn cho người đọc mã trong tương lai.

Nói chung, theo kinh nghiệm của tôi, cách tiếp cận này cho vay chính nó là súc tích hơn, ít lộn xộn hơn và rõ ràng hơn.

Chúc bạn may mắn!

1
type FunctionName = (n: returnType) => any; 

class ClassName { 
    save(callback: FunctionName) : void { 
     callback(data); 
    } 
} 

Điều này chắc chắn phù hợp với mô hình lập trình chức năng.

Các vấn đề liên quan