iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 7
1
自我挑戰組

Typescript 初心者手札系列 第 7

【Day 07】TypeScript 資料型別 - 基礎物件型別(Basic Object)

閱讀今天的文章前,先回顧一下昨天的學習,回答看看:

  • 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; }'.

來個重點整理吧:基礎物件的型別推論機制

  1. 物件的資料型別會依照物件的屬性或方法內容被推論出來
  2. 可以被接受的物件操作行為:
  • 可以覆寫相對應物件屬性且相同型別的值
  • 可以接受物件格式完全相同的整體物件覆寫
  1. TS 會報錯發出警告的情境:
  • 覆寫整個物件時,多或少物件屬性,或是屬性值的型別錯誤
  • 隨意新增原先不存在的物件屬性或方法
  • 覆寫錯誤的屬性型別值
  1. 注意:在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天,等著我來征服你吧!(握拳)


上一篇
【Day 06】TypeScript 資料型別 - 原始型別 (Primitive Types)
下一篇
【Day 08】TypeScript 資料型別 - 函式型別(Function Types)-(上)
系列文
Typescript 初心者手札30

1 則留言

0
samuelWang
iT邦新手 5 級 ‧ 2019-11-15 10:46:11

這篇解釋得非常詳細,對剛學的新手幫助很大

我要留言

立即登入留言