前面已經認識了 string、number 和 boolean,但閱讀 TypeScript 程式碼時,可能還會看到:
string | null
中間的 | 代表 Union Type,可以先理解成「或」。
因此:
string | null
表示這份資料可能是字串,也可能是 null:
string 或 null
它不是代表 TypeScript 不知道資料的型別,而是我們明確告訴 TypeScript:這裡可能有文字,也可能暫時沒有值。
null 代表什麼?null 通常用來表示「目前沒有值」,而且這個狀態是刻意設定的。
例如:
let selectedText: string | null = null
這段程式表示 selectedText 可以存放字串,但目前還沒有選擇任何內容,所以先使用 null。
之後選擇 Todo 時,就可以放入文字:
selectedText = '學習 TypeScript'
如果型別只有 string:
let selectedText: string = null
在開啟嚴格的 null 檢查時,TypeScript 會提出錯誤,因為 null 並不是字串。
所以加入 | null,就是把「目前可能沒有值」這種情況也寫進型別裡。
假設函式收到的文字可能是 null:
function showText(text: string | null) {
console.log(text.trim())
}
TypeScript 會提醒 text 可能是 null。
這是因為 trim() 是字串的方法,但 null 沒有這個方法。如果程式執行時拿到的是 null,就會發生錯誤。
使用前要先檢查:
function showText(text: string | null) {
if (text === null) {
console.log('目前沒有文字')
return
}
console.log(text.trim())
}
經過判斷後,TypeScript 知道後面的 text 已經不可能是 null,所以可以放心把它當成 string 使用。
這種透過條件判斷,將型別從:
string | null
縮小成:
string
的過程稱為 Narrowing,也就是「型別縮小」。
string | null假設要根據 id 尋找 Todo 的文字,可以這樣寫:
function findTodoText(id: number): string | null {
const todo = todos.find((todo) => todo.id === id)
if (!todo) {
return null
}
return todo.text
}
這個函式有兩種可能的結果:
string
null
因此函式的回傳型別是:
string | null
使用結果時,也要記得處理找不到資料的情況:
const text = findTodoText(1)
if (text === null) {
console.log('找不到這筆 Todo')
} else {
console.log(text)
}
TypeScript 要求我們檢查 null,是為了避免只想到「一定有資料」,卻忘記資料可能不存在。
null 和 undefined 一樣嗎?兩者都可以表示目前沒有可用的值,但並不是相同的東西。
目前可以先簡單理解成:
null:通常是開發者刻意設定目前沒有值undefined:通常表示內容還沒有被指定例如,JavaScript 的 find() 找不到資料時,回傳的是 undefined:
const todo = todos.find((todo) => todo.id === id)
所以 todo 可能是:
Todo | undefined
不論遇到 null 還是 undefined,重點都是在使用資料前,先確認它是否存在。
| 可以先理解成「或」string | null 表示資料可能是字串,也可能目前沒有值null 通常表示刻意設定的「沒有值」null
null 和 undefined 都能表示沒有值,但兩者並不相同string | null 這樣子的寫法只是把程式可能遇到的情況寫得更清楚,當之後再看到時就可以聯想到:這裡可能有文字,也可能目前什麼都沒有。
下篇見~