2015-09-17 14 views
20

Tôi vừa mới bắt đầu với TypeScript và tôi đang cố gắng hiểu tại sao định nghĩa đối tượng nội tuyến sau đây không được coi là hợp lệ. Tôi có một bộ sưu tập các đối tượng - kiểu của chúng không liên quan (với tôi), nhưng chúng thực hiện giao diện để khi tôi lặp qua chúng, tôi biết rằng các phương thức giao diện sẽ có mặt trong mỗi đối tượng trong bộ sưu tập.Thực hiện giao diện ẩn danh/nội tuyến trong TypeScript

Tôi đã xem qua một lỗi "biên dịch" khi tôi đã cố gắng để tạo ra một đối tượng với thông tin cá nhân cần thiết để thực hiện các phương pháp cần thiết:

interface Doable { 
    do(); 
} 

function doThatThing (doableThing: Doable) { 
    doableThing.do(); 
} 

doThatThing({ 
    private message: 'ahoy-hoy!', // compiler error here 
    do:() => { 
     alert(this.message); 
    } 
}); 

Thông điệp biên dịch lỗi là "Đối số loại '{ message: string, do:() => void; }' không thể chuyển nhượng Đối tượng chữ phải chỉ định các thuộc tính đã biết và 'thông báo' không tồn tại trong loại Doable ". Lưu ý rằng cùng một thông điệp được đưa ra nếu tôi xác định các đối tượng bên ngoài của cuộc gọi chức năng, tức là

var thing: Doable; 
thing = { 
    private message: 'ahoy-hoy!', // error here 
    do:() => { 
     alert(this.message); 
    } 
}; 
doThatThing(thing); 

Các lỗi tương tự xảy ra nếu tôi thêm phương pháp "bất ngờ" cũng như:

doThatThing({ 
    do:() => { 
     alert("ahoy hoy"); 
    }, 
    doSecretly:() => { // compiler error here now 
     alert("hi there"); 
    } 
}); 

Tôi nhìn JavaScript và phát hiện ra rằng this trong định nghĩa đối tượng inline bị scoped đến đối tượng toàn cầu:

var _this = this; // wait, no, why!? 
function doThatThing(doableThing) { 
    doableThing.do(); 
} 
doThatThing({ 
    message: 'ahoy-hoy!', 
    do: function() { 
     alert(_this.message); // uses global 
    } 
}); 

tôi đã cố gắng tìm kiếm thông tin trên INL ine triển khai các giao diện trong TypeScript, nhưng không thể tìm thấy bất cứ điều gì nói chuyện với vấn đề này cụ thể.

tôi có thể xác nhận rằng JS "cố định" được biên soạn công trình như dự định:

function doThatThing(doableThing) { 
    doableThing.do(); 
} 

doThatThing({ 
    message: 'ahoy-hoy!', 
    do: function() { 
     alert(this.message); 
    } 
}); 

... và có ý nghĩa đối với tôi, bởi vì (như xa như tôi hiểu) này được ngầm gọi constructor Object , vì vậy this nên được phạm vi cho đối tượng Object mới. Có vẻ như giải pháp duy nhất là khai báo mỗi lần thực hiện như một lớp thực hiện giao diện, nhưng điều đó thực sự cảm thấy hồi quy/nặng tay vì tôi chỉ có một cá thể của mỗi lớp. Nếu hợp đồng duy nhất với hàm được gọi là thực hiện giao diện, thì tại sao đối tượng không thể chứa các thành viên bổ sung?

Xin lỗi, đây hóa ra còn hơn tôi dự định ... trong Tóm lại, tôi hỏi:

  1. Tại sao mà thực hiện giao diện inline ("anonymous class", như sẽ được nói in Java) coi là vô hiệu trong TypeScript? Cụ thể, lỗi trình biên dịch đó có ý nghĩa gì và nó bảo vệ chống lại điều gì?
  2. Tại sao phạm vi phân bổ lại đối tượng toàn cầu được tạo trong JavaScript "được biên dịch"?
  3. Giả sử đó là lỗi của tôi (ví dụ: lỗi trình biên dịch là cần thiết để bảo vệ chống lại một số điều kiện không mong muốn), là giải pháp duy nhất thực sự khai báo một lớp một cách rõ ràng, như vậy?
interface Doable { 
    do() : void; 
} 

class DoableThingA implements Doable { // would prefer to avoid this ... 
    private message: string = 'ahoy-hoy'; 
    do() { 
     alert(this.message); 
    } 
} 

class DoableThingB implements Doable { // ... as well as this, since there will be only one instance of each 
    do() { 
     document.getElementById("example").innerHTML = 'whatever'; 
    } 
} 

function doThatThing (doableThing: Doable) { 
    doableThing.do(); 
} 

var things: Array<Doable>; 
things = new Array<Doable>(); 
things.push(new DoableThingA()); 
things.push(new DoableThingB()); 

for (var i = 0; i < things.length; i++) { 
    doThatThing(things[i]); 
} 

T.B. Lỗi trình biên dịch chỉ xuất hiện khi tôi nâng cấp lên TS 1.6 ngày hôm nay, mặc dù lỗi phạm vi lỗi trong JS được biên dịch xảy ra ở cả 1.6 và 1.5.

Cập nhật: François Cardinaux cung cấp một liên kết đến this answer, mà khuyến cáo sử dụng một loại khẳng định, nhưng này chỉ loại bỏ các lỗi biên dịch và thực sự gây ra một lỗi logic do phạm vi không đúng:

interface Doable { 
    do(); 
} 

function doThatThing (doableThing: Doable) { 
    doableThing.do(); 
} 

doThatThing(<Doable>{ // assert that this object is a Doable 
    private message: 'ahoy-hoy!', // no more compiler error here 
    do:() => { 
     alert(this.message); 
    } 
}); 

Nhìn vào JS đã biên dịch, điều này không chính xác:

var _this = this; // very wrong, and now hidden 
function doThatThing(doableThing) { 
    doableThing.do(); 
} 
doThatThing({ 
    message: 'ahoy-hoy!', 
    do: function() { 
     alert(_this.message); // s/b "this.message", which works in JS (try it) 
    } 
}); 

Trả lời

13

OK, cuối cùng tôi đã phát hiện ra vấn đề với câu hỏi 2 - Tôi đã sử dụng chất béo rrow => để khai báo phương pháp của đối tượng tại đây:

doThatThing(<Doable>{ 
    private message: 'ahoy-hoy!', 
    do:() => { // using fat arrow: global scope replaces new object's scope 
     alert(this.message); 
    } 
}); 

... mà "hút" phạm vi toàn cầu vào phương pháp. Vấn đề là cố định bằng cách sử dụng cú pháp lâu hơn, như vậy:

doThatThing(<Doable>{ 
    private message: 'ahoy-hoy!', 
    do: function() { // using "regular" anonymous function syntax, "this" meaning is preserved 
     alert(this.message); 
    } 
}); 

Vì vậy, trong bản tóm tắt:

  1. chưa được trả lời;
  2. Có lỗi đánh máy trong mã của tôi và tôi nên sử dụng "function()" thay vì "=>"; và,
  3. Loại xác nhận đối tượng bằng giao diện sẽ xóa lỗi trình biên dịch.
+1

Là một sidenote cho người đọc trong tương lai: Các hàm nội tuyến cũng có thể được xác định mà không có từ khóa 'function':' {message: 'ahoy-hoy!', Do() {alert (this.message); }} '. Cú pháp này chỉ là một cách viết tắt cho một hàm bình thường và không ràng buộc một hàm 'this' giống như hàm từ vựng. –

+0

Thay vào đó, đã sử dụng 'do =() => {...}' - phép gán đảm bảo nó sử dụng phạm vi cá thể 'Doable' ngay cả khi được gọi từ trình xử lý sự kiện, v.v. – Rycochet

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