【前端開發】TypeScript 的型別推論、型別註記與型別斷言

更新 發佈閱讀 34 分鐘

上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。

這一篇主要會來聊聊 TypeScript 初學者首先會遇到的幾個基礎概念,分別是:型別推論(Type Inference)、型別註記(Type Annotation)與型別斷言(Type Assertion)。

這幾個概念非常重要,如果想要深入了解 TypeScript 人一定會在 TypeScript 的官方文件或是 Stack overflow 上不斷遇到,建議在初學時就先大致了解。

在理解這幾個概念之前,建議大家要對 JavaScript 的型別系統、自動轉型的特性有基礎了解,並且了解自動轉型及缺乏型別定義的工具,會對開發上帶來什麼樣的困擾,如此才能理解今天要討論的主題可以解決什麼樣的問題。

那麼就讓我們接續之前的討論,先來聊聊 TypeScript 的型別註記系統吧:

TypeScript 的型別註記

型別註記在 TypeScript 中最基礎的概念,它可以協助開發者針對變數、參數、回傳值進行型別的標註,當註記的變數、參數及回傳值被帶入型別有誤的資料時,TypeScript 就會給予報錯。

我們來看看最基本的型別註記在 TypeScript 中是怎麼運作的,首先是最簡單的變數型別標註:

// 標註變數為字串型別
const name: string = 'Vivian';

我們會使用一個半形冒號,加上 JavaScript 中的型別來進行註記,上方的範例是將一個名為 name 的變數標註為字串型別,如果我們在標註好型別的變數戴上錯誤的型別的話,TypeScript 就會報錯:

// Type 'string' is not assignable to type 'number'.
const name: number = 'Vivian';

在使用靜態資料的狀況下我們其實很少會標註型別,這個我們後續會說明原因,接著來看看我們如何針對函式標註型別:

// 具名函式陳述式
function getString (str: string) : string {
return str
};

// 箭頭函式
const getString = (str: string): string => str;

在具名函式陳述式(Statement)中,我們可以在參數後面一樣加上冒號,在冒號後接續你想要標注的參數型別,針對回傳值的型別則接續在參數後加上冒號,接著標註你想要回傳的值型別。

不過通常我們滿少看到函式陳述式或是函式表達式(Expression)的,一般都是看到箭頭函式(Arrow Function)比較多,因為寫起來快速且看起來較為簡潔。 初學者可能會因為箭頭函式比較簡潔所以比較難理解標註的方式,不過這其實只要夠瞭解箭頭函式的運作方式,多看幾次就會習慣了:

// JavaScript 箭頭函式
const getString = str => str;

// TypeScript 箭頭函式
const getString = (str: string): string => str;

其實標註的方式跟一般的函式差不多,在參數後面一樣加上冒號,在冒號後接續你想要標注的參數型別,針對回傳值的型別則接續在參數後加上冒號,接著標註你想要回傳的值型別。

這樣我們就了解 TypeScript 中最基礎的型別標記啦,接著我們來看看 TypeScript 另外一個基礎、同時非常重要的概念:型別推論。

TypeScript 的型別推論

前文我們有提到,在使用靜態資料的狀況下我們其實很少會標註型別,這是為什麼呢?

由於 TypeScript 是透過靜態型別系統,在 JavaScript 編譯時透過上下文來「推斷」程式碼與型別標注的關係,例如:明明就標註回傳值要回傳字串型別,但卻回傳了數字,那麼 TypeScript 就會報錯。

所以其實在使用靜態資料的狀況下,我們其實就算不特別標註 TypeScript 也可以推論出指定變數的型別,以下範例在我們把滑鼠移到變數上時,TypeScript 會跳出它推論的出對應型別:

// let personName: string
let personName = '';

假設我指給這個變數錯誤的型別的話,TypeScript 一樣會報錯:

let personName = '';
// Type 'number' is not assignable to type 'string'.
personName = 123;

因此提供預設值在 TypeScript 中就會顯得特別重要,假設我們針對這個靜態資料沒有提供預設值,註解的地方是 TypeScript 顯示的型別提示:

// let personName: any
let personName;

// let personName: any
personName = 123;

// let personName: any
personName = '123';

會發現 TypeScript 會將沒有標註的型別變數推論成 any ,any 型別在 TypeScript 的意義是「可以接受任何型別的資料」,於是乎就讓我們的程式碼從 TypeScript 變回弱型別的 JavaScript 了,完全失去我們使用這個程式語言的意義。

雖然 TypeScript 擁有自動推論型別的功能,但最好只使用在「靜態、有預設值」的變數上,不然 TypeScript 可能會將回傳值的型別推論為 any,或是出現一些預期外的型別。

問題來了?對於函式的參數與回傳值如果都不標註型別,TypeScript 可以幫我們推論嗎?答案是:否,因為 TypeScript 無法針對在沒有前後文、沒有型別標註的未知參數進行推論,因此型別就會變成 any。

因此,也有開發者認為有限度的標註可以使 TypeScript 的程式碼更加簡潔且好維護,例如:針對函式嚴格標註、限制可被使用的型別,但靜態資料、預設值則讓 TypeScript 自動推論,我個人是很認同這種做法,給大家做參考。

TypeScript 的型別斷言

在 TypeScript 有一種酷東西叫做型別斷言(Type Assertion),這個算是自己在初學 TypeScript 時 最搞不懂的東西,在被自己一些沒寫好的 TypeScript 荼毒後,才理解所謂的斷言是怎麼一回事。

雖然可以把型別定義好是最理想的狀況,但有些狀況底下,還真的會有「未知(unknwon)型別」的出現,斷言就是用來處理未知型別的狀況。

關於 unknown 型別,大家可能最普遍會搞混的是:unknown 與 any 的差異是什麼?這個觀念也很重要,建議大家在初學 TypeScript 就可以養成好習慣:

unknown 是未知,any 是任意,未知並不代表這個變數想要接受「隨便一種」型別。

講了那麼多,讓我們來看看 TypeScript 官網針對斷言的範例:

const myCanvas = document.getElementById("main_canvas") as HTMLCanvasElement;

範例中用了 getElementById 這個方法去取得指定的 DOM 元素,不過 DOM 元素在 TypeScript 中也有屬於其對應的型別,舉例來說(此處僅列舉常用的型別):

  • HTMLElement:代表一般的 HTML 元素,如 <div><span> 等。它是最基本的 DOM 元素型別,包含了一些基本的屬性和方法。
  • HTMLInputElement:代表 <input> 元素,用於處理使用者輸入的表單元素。它擁有 HTMLInputElement 特有的屬性和方法,如 valuechecked 等。
  • HTMLSelectElement:代表 <select> 元素,用於選擇列表。它提供了相關的屬性和方法,例如 selectedIndexoptions 等。
  • HTMLTextAreaElement:代表 <textarea> 元素,用於多行文本輸入。它有自己特定的屬性和方法,如 valuerows 等。
  • HTMLButtonElement:代表 <button> 元素,用於創建按鈕。它提供了與按鈕相關的屬性和方法,如 disabledclick 等。

我們要怎麼知道透過 getElementById 這個方法去取得指定的 DOM 元素是哪一種?

面對未知的型別我們就可以在 TypeScript 中,在回傳值的後方使用 as 關鍵字,並接續你想要指定的型別,當然這裡不可以出現型別的衝突,舉例來說:

/* Conversion of type 'string' to type 'number' may be a mistake 
because neither type sufficiently overlaps with the other.
If this was intentional, convert the expression to 'unknown' first. */

const x = "hello" as number;

上方的範例中,明明是字串型別,我們卻把它斷言為數字型別,此時就會報錯,TypeScript 甚至會叫你把字串型別先轉換成 unknown 型別再進行斷言。

不過這樣的使用方式顯然不合理,要極力避免,且注意實際的回傳值要是否與斷言相吻合,所以大部分會使用斷言可能是在兩種狀況:在型別沒有被推斷且可為任意型別時:

const variable = <any> as <T>;

型別未知:

const variable = <unknown> as <T>;

由於 TypeScript 型別眾多,不免會出現像是選擇 DOM 元素時,出現未知型別的問題,除非必要,不然建議不要為了符合編譯器的提示而大量使用斷言,建議在一開始就針對回傳值好好地標註型別。

除了使用 as 關鍵字,我們也可以使用下方這種方式去斷言型別未知的變數(函式回傳值),使用大於小於的符號包住你想要斷言的型別:

const element = <T>document.getElementById("element");

實際使用起來可能會長這樣:

const myCanvas = <HTMLCanvasElement>document.getElementById("main_canvas");

這種用大於小於的方式相對少見,因為會跟 TypeScript 中的另外一個概念「泛型」很像,希望之後有機會可以介紹到,以上就是對於型別斷言的基礎介紹啦。

小結

這篇文章主要介紹了三個 TypeScript 中很重要的觀念,分別為:型別註記、型別推論與型別斷言,雖然了解這些觀念並沒有辦法讓你完整掌握 TypeScript 這門語言,但卻能讓我們在研讀相關程式碼、文件時更加順遂。

希望大家可以透過這篇文章,更加瞭解 TypeScript 的基礎概念,我是 Vivian,我們下次見。

參考資料:

  1. TypeScript Docs - Type Inference
  2. TypeScript Docs - Type Annotation
  3. TypeScript Docs - Type Assertion
留言
avatar-img
Vivian Yeh - 跨領域轉職的軟體工程師
459會員
104內容數
為了追求可以窩在座位上、可以心無旁騖思考問題、座位可以亂七八糟沒關係、不需要到處哈腰點頭跑客戶,不用腳踩十公分、連妝都可以不用化的職場人生,文組少女毅然決然踏上RD的養成日常。
2024/05/23
與 cookie 相比,localStorage 與 sessionStorage 的機制相對單純,兩者皆是瀏覽器中的儲存空間,與 cookie 最大的不同在於:localStorage 與 ⋯⋯
Thumbnail
2024/05/23
與 cookie 相比,localStorage 與 sessionStorage 的機制相對單純,兩者皆是瀏覽器中的儲存空間,與 cookie 最大的不同在於:localStorage 與 ⋯⋯
Thumbnail
2024/05/22
在瀏覽器環境中有許多的儲存空間,想要查看這些空間的話,可以透過「chrome > Dev Tools > Application > Storage」即能進行查看。 瀏覽器內存空間的差異不僅常常被拿來被當作面試考題,在實務開發中更扮演舉足輕重的角色,今天就想透過這系列的文章深度了解這些瀏覽器內存⋯
Thumbnail
2024/05/22
在瀏覽器環境中有許多的儲存空間,想要查看這些空間的話,可以透過「chrome > Dev Tools > Application > Storage」即能進行查看。 瀏覽器內存空間的差異不僅常常被拿來被當作面試考題,在實務開發中更扮演舉足輕重的角色,今天就想透過這系列的文章深度了解這些瀏覽器內存⋯
Thumbnail
2024/02/08
在前端的開發中,除了切版與串 API 外,大部分的時間都在針對表單內容進行檢核、驗證、阻擋,一方面是讓使用者在操作頁面的過程中有良好的使用者體驗,不會因為一些例外狀況(Edge Case),例如:莫名其妙的 4xx 錯誤,導致使用者卡在某個操作流程中逃不出來,另一方面是讓傳遞到後端的資料更加正確⋯⋯
Thumbnail
2024/02/08
在前端的開發中,除了切版與串 API 外,大部分的時間都在針對表單內容進行檢核、驗證、阻擋,一方面是讓使用者在操作頁面的過程中有良好的使用者體驗,不會因為一些例外狀況(Edge Case),例如:莫名其妙的 4xx 錯誤,導致使用者卡在某個操作流程中逃不出來,另一方面是讓傳遞到後端的資料更加正確⋯⋯
Thumbnail
看更多
你可能也想看
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
針對 JavaScript 中的原始型別和隱性轉型進行了詳細的探討
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
全新版本的《三便士歌劇》如何不落入「復刻經典」的巢臼,反而利用華麗的秀場視覺,引導觀眾在晚期資本主義的消費愉悅之中,而能驚覺「批判」本身亦可能被收編——而當絞繩升起,這場關於如何生存的黑色遊戲,又將帶領新時代的我們走向何種後現代的自我解構?
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
本章節旨在介紹 TypeScript 的基本資料型別,包括內建型別、型別轉換、自訂型別、元組、集合、陣列、和字典型別。透過理解和使用這些型別,可以提高代碼的可讀性和可維護性。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節是一個初級的 TypeScript 教學,主要介紹了 TypeScript 中物件導向程式設計的各種核心概念,包括類別、建構子、存取修飾子、繼承、多型、封裝、介面、抽象類別、靜態類別、列舉、委派、Lambda 表達式、泛型和反射等。每個概念都通過詳細的解釋和實例代碼來進行深入的介紹。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本章節旨在介紹TypeScript中的函數,包括其基本結構、如何呼叫函數、函數的參數以及函數的返回值等相關概念。通過本章節,讀者可以學習到如何在TypeScript中使用不同的方式來定義函數,如函數聲明、函數表達式、箭頭函數和匿名函數等。
Thumbnail
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
Thumbnail
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
本文深度解析賽勒布倫尼科夫的舞臺作品《傳奇:帕拉贊諾夫的十段殘篇》,如何以十段殘篇,結合帕拉贊諾夫的電影美學、象徵意象與當代政治流亡抗爭,探討藝術在儀式消失的現代社會如何承接意義,並展現不羈的自由靈魂。
Thumbnail
本文帶你深入探索 TypeScript 中的 satisfies 特性,能幫助你實現精確的型別推導與型別檢查。透過實際案例,展示如何使用 satisfies 提升代碼的型別安全與程式碼的整潔,是每位 TypeScript 開發者不可或缺的知識。
Thumbnail
本文帶你深入探索 TypeScript 中的 satisfies 特性,能幫助你實現精確的型別推導與型別檢查。透過實際案例,展示如何使用 satisfies 提升代碼的型別安全與程式碼的整潔,是每位 TypeScript 開發者不可或缺的知識。
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
5 月,方格創作島正式開島。這是一趟 28 天的創作旅程。活動期間,每週都會有新的任務地圖與陪跑計畫,從最簡單的帳號使用、沙龍建立,到帶著你從一句話、一張照片開始,一步一步找到屬於自己的創作節奏。不需要長篇大論,不需要完美的文筆,只需要帶上你今天的日常,就可以出發。征服創作島,抱回靈感與大獎!
Thumbnail
TypeScript是一種由Microsoft開發和維護的開源編程語言。它是JavaScript的超集,主要擴展了JavaScript的語法,增加了靜態類型檢查和其他特性,使得開發大型應用程序更為方便和可靠。
Thumbnail
TypeScript是一種由Microsoft開發和維護的開源編程語言。它是JavaScript的超集,主要擴展了JavaScript的語法,增加了靜態類型檢查和其他特性,使得開發大型應用程序更為方便和可靠。
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
Thumbnail
當時間變少之後,看戲反而變得更加重要——這是在成為母親之後,我第一次誠實地面對這一件事:我沒有那麼多的晚上,可以任性地留給自己了。看戲不再只是「今天有沒有空」,而是牽動整個週末的結構,誰應該照顧孩子,我該在什麼時間回到家,隔天還有沒有精神帶小孩⋯⋯於是,我不得不學會一件以前並不擅長的事:挑選。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
Thumbnail
本章節旨在介紹TypeScript的基本語法,包括一般結構、程式進入點、註解以及變數的定義和賦值。這些知識將幫助讀者瞭解TypeScript的基本架構,並且可以開始使用TypeScript進行開發。
追蹤感興趣的內容從 Google News 追蹤更多 vocus 的最新精選內容追蹤 Google News