2012-10-18 16 views
9

tôi đã chơi một chút với giao diện có chữ ký xây dựng trong nguyên cảo, và tôi đã trở thành một chút bối rối khi những sản phẩm sau thất bại trong việc gõ kiểm tra:Giao diện với chữ ký xây dựng không gõ kiểm tra

class Foo { 
    constructor() { 
    } 
} 

interface Bar { 
    new(): Bar; 
} 

function Baz(C : Bar) { 
    return new C() 
} 

var o = Baz(Foo); 

Lỗi loại được :

thông số Cung cấp không phù hợp với bất kỳ chữ ký của mục tiêu gọi: Xây dựng chữ ký của các loại 'mới() => Foo' và 'Bar' là không tương thích: loại 'Bar' đòi hỏi một chữ ký xây dựng, nhưng loại Thiếu 'Foo' s one (C: Bar) => Bar

Loại hàm tạo của Foo là() => Foo, và đó là điều tôi nghĩ Bar nói. Am i thiếu cái gì ở đây?

Trả lời

1

Vấn đề (ít nhất là từ quan điểm của trình biên dịch TypeScript) là chữ ký của phương thức Bar 'new. Nếu bạn thay thế định nghĩa của Bar bằng các thông số sau,

interface Bar { 
    new(): any; 
} 

hoạt động. Bạn cũng có thể sử dụng new(): Foo, chỉ Bar vì giá trị trả lại không hoạt động.

5

Đây là phiên bản cập nhật mã của bạn với một thay đổi nhỏ.

Chúng tôi xác định giao diện Bar với bất kỳ chức năng và biến nào mà chúng tôi mong đợi sẽ có mặt.

Tiếp theo, chúng tôi mở rộng giao diện Bar với giao diện NewableBar. Điều này chỉ định nghĩa một hàm tạo trả về một Bar.

Foo thực hiện Bar và có một hàm tạo và Baz yêu cầu một NewableBar, mọi thứ đều được chọn.

Đây là chi tiết hơn một chút so với any - nhưng cung cấp cho bạn kiểm tra bạn muốn.

interface Bar { 

} 

interface NewableBar extends Bar { 
    new(); 
} 

class Foo implements Bar { 
    constructor() { 

    } 
} 

function Baz(C : NewableBar) { 
    return new C() 
} 

var o = Baz(Foo); 
+0

Thay vì sử dụng 'bất kỳ' bạn sử dụng giao diện siêu (bạn có thể bỏ qua' triển khai' và 'mở rộng', btw). Đó là alright, tôi đoán, và tốt hơn so với 'any', nhưng một điều vẫn còn lỗi tôi: Tại sao bạn không thể để cho' NewableBar :: new() 'trả về một' NewableBar'? Tại sao nó phải là một loại ** chung hơn ** so với 'NewableBar' (và rõ ràng ít nhất là chung chung là' Foo')? –

+0

@AdrianLang Tôi đưa vào kế thừa và triển khai rõ ràng để rõ ràng, nhưng bạn đúng - TypeScript sẽ vui vẻ suy ra những điều đó nếu mọi thứ phù hợp. Có một vấn đề giải thích khi cố gắng xử lý chữ ký 'mới()' trên một phương thức như một kiểu cụ thể. – Fenton

+0

Nhưng, điều này xảy ra bất cứ khi nào bạn cố thêm bất kỳ thứ gì vào Foo. Chỉnh sửa: xin lỗi, tôi đã làm sai. Chữ ký cấu trúc của tôi phải là: 'new (... _: any []): Bar; ' – farre

1

Tôi nghĩ mình biết bạn đang dùng cái này ở đâu và tôi nghĩ bạn cần một cách tiếp cận khác biệt tinh tế.

Ví dụ này cho biết như sau:

  • Baz phải được thông qua một mục đó là newable.
  • Baz sẽ trả về một Bar
  • Không phải tất cả của Bar cần phải newable, chỉ những được truyền cho Baz

Dưới đây là ví dụ:

interface Bar { 
    sayHello(name: string): void; 
} 

interface Newable { 
    new(); 
} 

class Foo implements Bar { 
    constructor() { 

    } 

    sayHello(name: string) { 
     window.alert('Hello ' + name); 
    } 
} 

function Baz(C : Newable) { 
    return <Bar> new C() 
} 

var o = Baz(Foo); 
o.sayHello('Bob'); 

Sự nguy hiểm duy nhất của này cách tiếp cận là bạn có thể vượt qua một cái gì đó mới mà không phải là một chức năng Bar để Baz.Khi bạn đang sử dụng tính năng động bằng cách tạo đối tượng từ đối số, điều này phần lớn là không thể tránh khỏi trừ khi bạn sẵn sàng vượt qua đối tượng được khởi tạo trước, trong trường hợp đó Baz sẽ vui vẻ chấp nhận một thanh, chứ không phải là mới.

+0

Có, một cái gì đó dọc theo những dòng này là những gì tôi muốn đạt được. Ngoại trừ việc tôi muốn 'Bar' và' Newable' là một giao diện. Cảm ơn. – farre

1

Tôi biết đây là một câu hỏi cũ, nhưng tôi đã có nhu cầu cho một cái gì đó tương tự như ngày hôm nay và đã xem qua bài đăng. Sau một số thử và sai tôi đến với các giải pháp sau đây:

interface Bar { 
    sayHello(name: string); 
} 

class Foo implements Bar { 
    sayHello(name: string) { 
     window.alert("Hello " + name); 
    } 
} 

function Baz(c: new() => Bar) { 
    return new C(); 
} 

var o = Baz(Foo); 
o.sayHello("Bob"); 

Về cơ bản giao diện chỉ có thể xác định hợp đồng của một thể hiện của một đối tượng, vì vậy đòi hỏi phải có một constructor nhất định để tồn tại phải được thực hiện tại các chức năng đó sẽ là gọi hàm tạo. Phương pháp này cũng phát độc đáo với generics:

function Baz<T extends Bar>(c: new() => T) { 
    return new c(); 
} 

var o = Baz(Foo); 

Trong ví dụ trên biến "o" sẽ được suy ra dưới dạng Foo.

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