Trong bản đánh máy, cái gì là! Toán tử (dấu chấm than / bang) khi hủy bỏ thành viên?


453

Khi nhìn vào mã nguồn cho quy tắc tslint, tôi đã xem qua tuyên bố sau:

if (node.parent!.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

Thông báo cho người !vận hành sau node.parent. Hấp dẫn!

Lần đầu tiên tôi thử biên dịch tệp cục bộ với phiên bản TS (1.5.3) hiện đang cài đặt của tôi. Lỗi kết quả chỉ vào vị trí chính xác của tiếng nổ:

$ tsc --noImplicitAny memberAccessRule.ts 
noPublicModifierRule.ts(57,24): error TS1005: ')' expected.

Tiếp theo tôi nâng cấp lên TS mới nhất (2.1.6), đã biên dịch nó mà không gặp vấn đề gì. Vì vậy, nó dường như là tính năng của TS 2.x. Nhưng sự dịch chuyển hoàn toàn bỏ qua tiếng nổ, dẫn đến kết quả là:

if (node.parent.kind === ts.SyntaxKind.ObjectLiteralExpression) {
    return;
}

Google fu của tôi cho đến nay đã làm tôi thất bại.

Toán tử dấu chấm than của TS là gì và nó hoạt động như thế nào?

Câu trả lời:


688

Đó là toán tử khẳng định không null. Đây là một cách để nói với trình biên dịch "biểu thức này không thể nullhoặc undefinedở đây, vì vậy đừng phàn nàn về khả năng của nó nullhoặc undefined". Đôi khi trình kiểm tra loại không thể tự đưa ra quyết định đó.

Nó được giải thích ở đây :

Một !toán tử biểu thức sửa lỗi mới có thể được sử dụng để khẳng định toán hạng của nó là không rỗng và không xác định trong các ngữ cảnh trong đó trình kiểm tra kiểu không thể kết luận thực tế đó. Cụ thể, hoạt động x!tạo ra một giá trị của loại xnullundefinedloại trừ. Tương tự như các xác nhận kiểu của các biểu mẫu <T>xx as T, !toán tử xác nhận không null được loại bỏ đơn giản trong mã JavaScript được phát ra.

Tôi thấy việc sử dụng thuật ngữ "khẳng định" một chút sai lệch trong lời giải thích đó. Đó là "khẳng định" theo nghĩa là nhà phát triển đang khẳng định nó , không phải theo nghĩa là một bài kiểm tra sẽ được thực hiện. Dòng cuối cùng thực sự chỉ ra rằng nó không dẫn đến mã JavaScript được phát ra.


102
Cuộc gọi tốt về sự mơ hồ 'khẳng định'.
Bình Estus

8
Lời giải thích hay. Tôi thấy đó là một cách thực hành tốt để thực hiện một console.assert()biến trong câu hỏi trước khi nối thêm !sau đó. Bởi vì add !đang báo cho trình biên dịch bỏ qua kiểm tra null, nó biên dịch thành noop trong javascript. Vì vậy, nếu bạn không chắc chắn rằng biến đó là null, thì tốt hơn nên thực hiện kiểm tra xác nhận rõ ràng.
Jayesh

12
Như một ví dụ động lực: sử dụng loại Bản đồ ES mới với mã như dict.has(key) ? dict.get(key) : 'default';trình biên dịch TS không thể suy ra rằng getcuộc gọi không bao giờ trả về null / không xác định. dict.has(key) ? dict.get(key)! : 'default';thu hẹp các loại chính xác.
Kitsu.eb

1
Có tiếng lóng cho toán tử này, giống như cách toán tử Elvis đề cập đến toán tử nhị phân?
ebakunin

@Jayesh bạn có thể mở rộng trên console.assert () thực hành tốt không, bạn có thể đăng một ví dụ không?
Christopher Francisco

168

Câu trả lời của Louis rất hay, nhưng tôi nghĩ tôi sẽ cố gắng tóm tắt nó một cách cô đọng:

Toán tử bang bảo trình biên dịch tạm thời nới lỏng ràng buộc "không null" mà nó có thể yêu cầu. Nó nói với trình biên dịch: "Là nhà phát triển, tôi biết rõ hơn bạn rằng biến này không thể là null ngay bây giờ".


85
Sau đó, là nhà phát triển, bạn đã nhầm lẫn.
Mike Chamberlain

8
Hoặc, như trình biên dịch, nó đã gây rối. Nếu hàm tạo không khởi tạo một thuộc tính nhưng hook vòng đời thực hiện nó và trình biên dịch không nhận ra điều này.
Mukus

26
Đây không phải là trách nhiệm của trình biên dịch TS. Không giống như một số ngôn ngữ khác (ví dụ: C #), JS (và do đó TS) không yêu cầu các biến được khởi tạo trước khi sử dụng. Hoặc, để xem xét nó theo một cách khác, trong JS, tất cả các biến được khai báo có varhoặc letđược khởi tạo ngầm undefined. Hơn nữa, các thuộc tính thể hiện của lớp có thể được khai báo như vậy, vì vậy class C { constructor() { this.myVar = undefined; } }là hoàn toàn hợp pháp. Cuối cùng, móc vòng đời phụ thuộc vào khung; ví dụ Angular và React thực hiện chúng khác nhau. Vì vậy, trình biên dịch TS không thể được mong đợi để lý do về chúng.
Mike Chamberlain

1
Có trường hợp sử dụng hợp lệ cho toán tử bang xem xét sự khủng khiếp của phân tích loại dựa trên dòng điều khiển trong TS không?
Eugene Karataev

@EugeneKarataev Có, các khung thường khởi tạo các biến bên trong chính chúng và phân tích luồng điều khiển ts không thể bắt được nó. Việc sử dụng chắc chắn đã giảm, nhưng bạn sẽ bắt gặp những trường hợp bạn cần.
arg20
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.