Tại sao 'instanceof' trong TypeScript lại cho tôi lỗi “'Foo' chỉ đề cập đến một kiểu, nhưng đang được sử dụng như một giá trị ở đây.”?


91

Tôi đã viết mã này

interface Foo {
    abcdef: number;
}

let x: Foo | string;

if (x instanceof Foo) {
    // ...
}

Nhưng TypeScript đã cho tôi lỗi này:

'Foo' only refers to a type, but is being used as a value here.

Tại sao chuyện này đang xảy ra? Tôi nghĩ rằng điều đó instanceofcó thể kiểm tra xem giá trị của tôi có một kiểu nhất định hay không, nhưng TypeScript dường như không thích điều này.


Xem câu trả lời dưới đây @ 4castle. Nếu không, bạn đúng, tôi sẽ làm cho nó Foo | string.
Daniel Rosenwasser


Và có thể trùng lặp của Kiểm tra xem biến là một loại giao diện cụ thể trong một đoàn nguyên cảo (Tôi không thực sự muốn một tay búa này)
Cerbrus

@Jenny O'Reilly, bây giờ đó chắc chắn là một bản sao của một bản sao Có thể xảy ra!
marckassay 27/12/18

Câu trả lời:


100

Chuyện gì đang xảy ra

Vấn đề là đó instanceoflà một cấu trúc từ JavaScript và trong JavaScript, instanceofmong đợi một giá trị cho toán hạng bên phải. Cụ thể, trong x instanceof FooJavaScript sẽ thực hiện kiểm tra thời gian chạy để xem liệu có Foo.prototypetồn tại ở bất kỳ đâu trong chuỗi nguyên mẫu của x.

Tuy nhiên, trong TypeScript, interfaces không có bộ phát. Điều đó có nghĩa là không Foohoặc Foo.prototypetồn tại trong thời gian chạy, vì vậy mã này chắc chắn sẽ bị lỗi.

TypeScript đang cố gắng cho bạn biết điều này không bao giờ có thể hoạt động. Foochỉ là một loại, nó không phải là một giá trị nào cả!

"Tôi có thể làm gì thay vì instanceof?"

Bạn có thể xem xét các bảo vệ kiểu và bảo vệ kiểu do người dùng xác định .

"Nhưng nếu tôi vừa chuyển từ an interface sang a classthì sao?"

Bạn có thể bị cám dỗ để chuyển từ một interfacesang a class, nhưng bạn nên nhận ra rằng trong hệ thống kiểu cấu trúc của TypeScript (nơi mọi thứ chủ yếu dựa trên hình dạng ), bạn có thể tạo ra bất kỳ đối tượng nào có hình dạng giống như một lớp nhất định:

class C {
    a: number = 10;
    b: boolean = true;
    c: string = "hello";
}

let x = new C()
let y = {
    a: 10, b: true, c: "hello",
}

// Works!
x = y;
y = x;

Trong trường hợp này, bạn có xvà loại yđó có cùng một loại, nhưng nếu bạn thử sử dụng instanceoftrên một trong hai, bạn sẽ nhận được kết quả ngược lại với loại còn lại. Vì vậy, instanceofsẽ không thực sự cho bạn biết nhiều về kiểu nếu bạn đang tận dụng các kiểu cấu trúc trong TypeScript.


2
Tôi sẽ mất nhiều tuổi để phát hiện ra cái đó cho chính mình!
Matthew Layton

Vì vậy, về cơ bản tôi không hiểu được ý tưởng từ câu trả lời nào tốt hơn nên đi cùng. Lớp học? bởi vì bạn đã trình bày chi tiết. Nhưng đồng thời bối rối khi bạn đề cập "bạn có thể bị cám dỗ". Vì vậy, điều gì sẽ xảy ra nếu tôi phải so sánh tất cả các thuộc tính chứ không chỉ tài sản bơi như trong tài liệu cho các vệ sĩ loại?
HalfWebDev

7
Điểm chính ở đây là instanceofhoạt động với các lớp, không phải giao diện. Nghĩ rằng cần phải được nhấn mạnh.
vô tổ chức

5

Để thực hiện kiểm tra kiểu trong thời gian chạy với một giao diện đang sử dụng các bộ bảo vệ kiểu , nếu giao diện bạn muốn kiểm tra có các thuộc tính / chức năng khác nhau .

Thí dụ

let pet = getSmallPet();

if ((pet as Fish).swim) {
    (pet as Fish).swim();
} else if ((pet as Bird).fly) {
    (pet as Bird).fly();
}

Điều gì sẽ xảy ra nếu tôi tìm hiểu về vịt và thêm hàm bơi () vào giao diện Bird của mình? Có phải mọi vật nuôi đều được phân loại là cá trong một loại bảo vệ? Và nếu tôi có ba giao diện với ba chức năng, mỗi hai chức năng trùng lặp với một trong các giao diện khác?
Kayz

1
@Kayz nếu bạn không có thuộc tính / chức năng xác định duy nhất một giao diện, bạn không thể thực sự phân biệt chúng. Thú cưng của bạn thực sự có thể là một Duck, bạn nhập bảo vệ nó trở thành Fish, nhưng vẫn không có ngoại lệ thời gian chạy khi bạn gọi swim(). Đề nghị bạn tạo 1 cấp độ của giao diện chung (ví dụ Swimmable) và di chuyển các swim()chức năng của bạn ở đó, sau đó gõ bảo vệ trông vẫn tốt ((pet as Swimmable).swim.
Lee Chee Kiam

Để ngăn chặn đánh máy, bạn có thể sử dụng 'swim' in petđiều kiện. Nó sẽ thu hẹp nó xuống một tập hợp con phải swimđược xác định (ví dụ Fish | Mammal:)
Akxe

2

Daniel Rosenwasser có thể đúng và tuyệt vời nhưng tôi cảm thấy muốn sửa đổi câu trả lời của anh ấy. Bạn hoàn toàn có thể kiểm tra phiên bản của x, hãy xem đoạn mã.

Nhưng cũng dễ dàng như nhau để gán x = y. Bây giờ x sẽ không phải là một thể hiện của C vì y chỉ có hình dạng của C.

class C {
a: number = 10;
b: boolean = true;
c: string = "hello";
}

let x = new C()
let y = {
    a: 10, b: true, c: "hello",
}

console.log('x is C? ' + (x instanceof C)) // return true
console.log('y is C? ' + (y instanceof C)) // return false

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.