- Published on
[學習筆記] 初入 TypeScript 世界 (2):型別 Type
Article Directory
- TypeScript 的型別
- 空值 Void:沒有回傳值
- 任意型別 any:不檢查型別
- Never:不會有回傳值
- 陣列型別 Array
- 列舉型別 enum
- 未知型別 unknown
TypeScript 和 JavaScript 最明顯可見的差異就是型別,JavaScript 是弱型別語言,TypeScript 是原生 JavaScript 的延伸,在編譯後會生成 *.js
的程式碼供使用,TypeScript 的誕生主要也是要來解決 JavaScript 型別的問題。
TypeScript is a programming language that adds types to JavaScript.
TypeScript 的型別
大家熟悉的 JavaScript 資料型別有兩種,原始資料型別(boolean, number, string, null, undefined, Symbol)和物件型別(Object, Array, Function)。
之前的文章可以複習:
- [學習筆記] JavaScript 的複雜資料類型(1):物件 Object
- [學習筆記] JavaScript 的複雜資料類型(2):陣列 Array 及陣列方法 Array Method
- [學習筆記] JS ES6 中的新資料型別:Symbol
在 TypeScript 中,除了上面這些既有的,還增加了空值(Void)、任意型別(any)和 Never 這三個特殊型別
Void
:沒有回傳值
- 空值 只能賦值為 null 或 undefined
any
:不檢查型別
- 任意型別 類似回歸 JS 的弱型別,程式不管變數的資料型別也不管之後有沒有被賦值,但是濫用 any
的話等於失去使用 TypeScript 開發的意義了!
any
型別的變數,可以操作任意型別的屬性或方法
Never
:不會有回傳值
- 代表函式進入無窮迴圈或被中斷執行,永遠不會有回傳值的狀況,常用於函式的除錯
Array
:
- 陣列型別 陣列又分為以下四種
type[]
:表示資料為陣列,以及裡面的值的型別
1. 型別+方括號 const years: number[] = [2020, 2021, 2022, 2023]
宣告後,陣列中的項就不允許出現其他型別
const years: number[] = [2020, 2021, '2022', 2023]
// Type 'string' is not assignable to type 'number'
常使用 any 來表示陣列中允許出現任意型別
const arr: any[] = [2, 'Amy', { email: 'amy@gmail.com' }]
Array<elemType>
2. 陣列泛型 Array Generic:const years: Array<number> = [2020, 2021, 2022, 2023]
3. 用介面 Interface 表示陣列
這個之後筆記介面 Interface 的時候會詳細說明
4. 類別陣列 Array-like Object
enum
- 列舉型別 使用上與 JS 的物件類似,但可將變數的範圍限制在某些限制下進行存取並賦予定義,可以讓程式碼更好維護,也增加可讀性
// 宣告一個名為 Week 的 Enum type 變數
enum Week {
Sunday,
Monday,
Tuesday,
Wednesday,
Thursday,
Friday,
Saturday,
}
const today: Week = Week.Friday
console.log(today === Week.Friday) // true
console.log(Week[5]) // Friday
console.log(Week['Friday']) // 5
//將Week內的變數指向字串
enum Week {
Sunday = 'Sun',
Monday = 'Mon',
Tuesday = 'Tue',
Wednesday = 'Wed',
Thursday = 'Thu',
Friday = 'Fri',
Saturday = 'Sat',
}
console.log(Week[5]) // Friday
console.log(Week['Fri']) // undefined
console.log(Week['Friday']) // Fri
console.log(Week.Friday) // Fri
參考資料:https://medium.com/@notwist123/typescript-列舉型別-enumerate-96fc2eedd581
unknown
- 未知型別 這是 TS3.0 新增的型別,可以說是 any
型別的安全版本
any
一樣)
1. 可以接受任何型別賦值(和 unknown
型別的變數可以接受被賦予任何型別的值
let value: unknown
value = true
value = 10
value = 'Hello'
value = []
value = {}
value = null
value = undefined
value = new TypeError()
value = Symbol('type')
unknown
型別只能賦值給 any
和 unknown
自己
2. unknown
型別的變數只能被賦予給型別為 any
或 unknown
的變數,若賦值給其他型別的變數都會報錯
unknown
代表對值一無所知,因此無法賦值給明確的型別
let value: unknown
let value1: unknown = value
let value2: any = value
let value3: boolean = value // Error
let value4: number = value // Error
let value5: string = value // Error
let value6: object = value //Error
let value7: any[] = value //Error
let value8: void - value // Error
unknown
型別時,所有的屬性或方法都會報錯
3. 變數被註記為 相較於 any
型別,限制了屬性及方法的操作,讓 unknown
型別不如 any
型別的行為那樣難以控制
會報錯的特性,也提升了程式碼的維護性
unknown
型別要進行限縮才能使用屬性或方法
4. - 型別檢測 type guard
// 宣告一型別為 unknown 的變數
let isUnknown: unknown
// Error: Type 'unknown' is not assignable to type 'number'
let value: number = isUnknown
// 限縮變數的型別後,就可以賦值 unknown 型別值給變數
if (typeof isUnknown === 'number') {
value = isUnknown
}
- 型別斷言 Type Assertion
先將 unknown
型別的參數斷言為別的型別,即可以使用該斷言型別的屬性及方法
const value: unknown = 'Hello'
const someStr: string = value as string
const otherStr = someStr.toUpperCase() // HELLO
5. 在聯合型別中出現的話,可以簡化
若在聯合型別中含有 unknown
型別,如: unknown | string
其實可以直接簡化為unknown
,因為有了 unknown
,該變數就可以接受任何型別的值,string
型別的定義就沒有意義
Literal Types
◆ 字面值型別 用來限定變數只能使用列舉的值
type brand: 'iphone' | 'android' | 'samsung'
Type Aliases
◆ 型別別名 型別別名是用來給型別取一個新名字,常用在聯合型別
如果這個聯合型別會一直重複出現在程式碼中,就可以幫他取一個別名,作為之後方便使用在定義型別時的代稱
type StringOrNum = string | number
// 下面兩個相等
type objWithName = { name: string; id: StringOrNum }
type objWithName2 = { name: string; ud: string | number }
//----------------------
type Book = {
name: string
price: number
}
const book1: Book = {
name: 'Learn Typescript',
price: 250,
}
Generics
◆ 泛型 指在定義函式、介面或類別時,不預先指定型別,而是在使用的時候在指定型別的特性,形式通常為 <type>
。
前面介紹陣列型別時,也有提到陣列泛型的定義方式:
const arr: number[] = [1, 2, 3]
const arr2: Array<number> = [1, 2, 3]
const printArr: number[] = (arr: number[]) => {
console.log(arr)
}
const printArr: Array<number> = (arr: Array<number>) => {
console.log(arr)
}
上面定義兩個只接收數字的陣列,但如果想要在使用的時候,再決定陣列是字串還是數字的話,那就可以用泛型來處理。
在函式後面加上 <Type>
表示動態型別,<Type>
的命名是可以自己定義的,常見的是 <T>
和 <Type>
。
然後將參數 arr 指定為此型別,函式也回傳 Type[]
,這樣就能依據傳入陣列的型別去定義回傳的型別資料。
const printArr<Type>: Type[] = (arr: Type[]) => {
console.log(arr)
}
useState
最好是用泛型的方法定義型別
React 中的 如果 state 單純(非物件),也可以用給預設值的方式定義型別,如果是複雜的物件,就可以搭配泛型
// useState 的預設值留空
const [content, setContent] = useState<string>()
type Device = {
brand: string
price: number
}
const [device, setDevice] = useState<Device>()
// 給預設值,讓 TS 推論型別
const [content, setContent] = useState('')
打一打不小心有點多,今天就先到這裡啦~
參考資料: