TypeScript

TypeScript - Non-null assertion operator - !

陳建融 Randy Chen 2023/07/22 17:22:17
615

起源

在 Angular 的元件定義檔裡,時常會在宣告某些元件的成員變數的時候,在它們後面加上 ! 的符號,
這一篇文章就是來介紹一下,在這些成員變數後面加上 ! 的作用是什麼。

 

 

在變數宣告時,加入 ! 這個後綴修飾 的作用

! 加在某些屬性或變數的後面,用意為告訴 TS 這個屬性或變數的值,不可能是 null undefined,所以,不要對這個屬性或變數提出有可能為 nullundefined 的警示。

以上這種會跳出該屬性值可能為 null 或 undefined 提示的環境是你必需要啟動 TS 的 strict null checking mode 的檢查才會跳出以上的提示警訊,
若想要啟動這個檢查, 你必須要在專案檔裡面的 tsconfig.json 檔案,加入 strictNullChecks 這個設定,寫法如下

 

- - - - - - 我是分隔線 - - - - - -

接下來就來寫一些,使用後綴修飾 ! 的情境

Case 1

接著,你應該就可以在你的畫面上看到以下的錯誤提示

會出現以上的原因就是因為 arg 這個參數是有可能為 undefined 的, 因為,在傳入參數的部份,
我寫了 arg?: {name: string} 這個 arg 後面跟著的 ? 就是在告訴 TS 這個參數是可有可無的。
那可有可無就代表有可能沒有傳入任何東西,在這種情況下 arg 就是 undefined 的狀態了,
所以,你對一個是 undefined 的對象去調用 name 屬性, TS 當然會報錯囉!!

 

Case 1 - Solution

 

要解決以上的錯誤有以下兩種寫法

way 1. 自己撰寫防護機制

 

加入以上那一行後,就不會跳錯囉,因為,當 arg 為 nullundefined 的狀態,
就會進到那個判斷式,就會直接 return,不會進到後面的調用 name 屬性的部分囉。

 

way 2. 加上 exclamation mark !

但是以上這種寫法是很危險的喔,雖然,TS 不再報錯了,但換成瀏覽器報錯了,像下面這張圖這樣:

 

 

Case 2 - property initialization in Angular

在 Angular 的元件定義檔中,變數宣告的時候,如果只有為該變數定義它的型別的話,應該會報出以下的錯誤

上面錯誤訊息是說 info 這個變數並沒有被初始化且沒有在 constructor 中為這個 info 變數設值。
上面這個錯誤,是因為 TS 的這個設定 strictPropertyInitialization 而跳出的提示訊息。

 

Case 2 - Solution

way 1. 為該 property 設初始值

way 2. 在該元件的 constructor 為該 property 設初始值

way 3. 直接在該 property 宣告的地方,加入 exclamation mark 來消除以上的錯誤提示

 

第三種寫法,比較快速,
但是,你在該元件的 html template 第一次調用該值時,會跳出這個錯誤 Cannot read properties of undefined (reading 'name')
因為,我們並沒有為 info 這個物件設初始值,所以,在 HTML template 上第一次調用 info 物件的 name 屬性值當然會噴錯。

這種錯誤時常會出現在當某個值需要在 api 完成回覆之後,我們才會為該變數值設值,
但是,當 api 還沒完成回覆之前該變數值會是 null 也就自然會拋出以上這種 對於一個 undefined 的對象取用某個屬性值的錯誤。

但要解決以上的錯誤也不難,只要加上 ngIf=”info" ,即當該物件有值的時候,才在 HTML 上顯示該物件的值,也就不會再發生以上錯誤囉~ 寫法就像這樣

 

 

Conclusion

以上我們可以知道 在某些變數的後面加上 exclamation mark 雖然可以讓 TS 不再報錯,
但蠻危險的,等同於挖一個隱性的炸彈給未來的自己。
除非,你真的知道該值真的不會沒有值,才用吧,或者就加上一些額外的判斷,來預防未來可能對 undefined 的對象取值而造成的錯誤。

 

Reference

1. adding exclamation mark to Component’s properties
2. the usage of exclamation mark
3. TS official Docs about Non-null assertion operator

陳建融 Randy Chen