閱讀今天的文章前,先回顧一下昨天的學習,回答看看:
- TypeScript 中有哪些資料型別是 JS 和 TS都支援的呢?
- Null 和 Undefined 的差異和使用情境?
如果有點不清楚答案的話,可以看看 Day06 的文章喔!
在 JS 中我們會透過下面的程式碼來創建一個物件
let girl = {
name: 'Kira',
age: 18,
};
在 TS 中也是一樣的,同樣創建了一個物件 girl,該物件擁有兩個屬性 name、age ,雖然沒有宣告型別,貼心的 TS 便會自動幫忙做型別推論,告訴你 firstname 和 lastname 屬性是字串型別,而 age 屬性是數字型別。
let girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18
};
等等,那如果值是 undefined 或是 null呢? Nullable 型別總是讓人怕怕
是滴,這裡會需要特別注意。在預設狀況下(strictNullCheck 為 false),值為 undefined 或 null會被推論為 any型別,因為這時候 undefined 和 null 可以是任何資料型別的值。
let girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18,
marriage: undefined,
gender: null,
};
但如果 strictNullCheck 為 true,這時候 undefined 和 null 就會獨立出來,不能成為其他資料型別的值,這時候,聰明的 TS 就會合理的推論其為各自的型別了。
對於 strictNullCheck 設定 對 null 和 undefined 型別的影響,更多說明看Day 06 的文章
下面是在 TS 中幾個使用基礎物件常會出現錯誤警告的狀況:
倘若物件的屬性名稱改變、少或多了屬性,都會報錯
let girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18,
};
//物件的屬性名稱改變,報錯
girl = {
name1: 'Kira',
name2: 'Yang',
number: 18,
}
//少了age屬性,又報錯
girl = {
firstname: 'Kira',
lastname: 'Yang',
}
//多了hasPet屬性,還是報錯 > <
girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18,
hasPet: false,
}
let girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18,
};
//重新賦值(同資料型別),則OK
girl.firstname ='Una';
girl.lastname = 'Lin';
girl.age = 20
//重新賦值(不同資料型別),則報錯
girl.firstname ='Una';
girl.lastname = 'Lin';
girl.age = '1' // Error
倘若是增加原本沒有的方法,TS 也會嚴格的檢視,不符合原本設定的屬性就報錯
let girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18
};
girl.sayHello = function(){ return "hello";}
//Property 'sayHello' does not exist on type '{ name: string; age: number; }'.
來個重點整理吧:基礎物件的型別推論機制
- 物件的資料型別會依照物件的屬性或方法內容被推論出來
- 可以被接受的物件操作行為:
- 可以覆寫相對應物件屬性且相同型別的值
- 可以接受物件格式完全相同的整體物件覆寫
- TS 會報錯發出警告的情境:
- 覆寫整個物件時,多或少物件屬性,或是屬性值的型別錯誤
- 隨意新增原先不存在的物件屬性或方法
- 覆寫錯誤的屬性型別值
- 注意:在strictNullCheck 設定不同情況下,null 和 undefined 值的型別推斷不同
當然,TS 也可以透過型別註記(Type Annotation)方式明確宣告物件型別,下面程式碼變數 girl 註記為物件型別
let girl :object = {
firstname: 'Kira',
lastname: 'Yang',
age: 18
};
那使用型別註記的物件行為會和型別推論一樣嘛?來試看看吧!
//多了一個屬性greet => 型別推論會報錯,但型別註解OK
girl = {
firstname: 'Kira',
lastname: 'Yang',
age: 18,
greet :'hello'
}
//少了一個屬性 => 型別推論會報錯,但型別註解OK
girl = {
firstname: 'Kira',
lastname: 'Yang',
}
//屬性全改變 => 型別推論會報錯,但型別註解OK
girl = {
greet :'hello'
}
哪泥,似乎不太一樣呢!使用型別註解機制,無論物件的內容是什麼,都可以完全覆蓋, TS 都可以接受。
//重新賦值(同資料型別) => 型別推論OK,但型別註解報錯
girl.firstname ='Una';
girl.lastname = 'Lin';
girl.age = 20
//重新賦值(不同資料型別) => 型別推論報錯,型別註解一樣報錯
girl.firstname ='Una';
girl.lastname = 'Lin';
girl.age = '1' // Error
在此情境下,表現結果也和型別推論有些不同,物件屬性值的覆寫不被接受(即使型別相同也不行!)
//推論報錯,註解一樣報錯
girl.greet = 'hello'
在此情境下,結果和型別推論相同。
從上面三種情境的測試,你會發現使用型別註記,只有完全覆寫物件是可以被 TS 接受的,儘管物件屬性格式不同也可以!但任何物件內部的微調都不行(即使是與屬性對應的相同型別的值都無法寫入),也就是說,物件要覆寫就得全部覆寫!這個概念似乎跟 Immutable 物件很類似,一樣創建後屬性就無法更改,要換就要整個物件換掉。
來個重點整理吧:基礎物件型別註記
let A: object;
- A 可以被任何物件覆寫,內部格式不限
- A 只能進行全面覆寫,不能進行物件內部調整,包括新增屬性、改變屬性的值等
今天我們探討了物件型別中的基礎物件型別推論及型別註解,知道兩者機制下 TS 會採取不同方式檢視物件的操作行為,並決定是否報錯,那我們明天繼續吧!
總算總算...鐵人賽過了一週啦(撒花~),有種度日如年的感覺,每天在有限時間內學習新技術,然後把學習整理成別人看得懂的文章真是太精崩實潰了,有部分觀念的理解仍然有點薄弱,但還是試著寫出來。如果剛好有大神不小心經過,看到怪怪或錯誤的地方,歡迎留言告知!
胎斯潰噴,接下來還有23天,等著我來征服你吧!(握拳)