[TypeScript] 快速上手 satisfies,讓你輕鬆推論型別與類型檢查

閱讀時間約 7 分鐘
TypeScript - satisfies

TypeScript - satisfies


想必大家在開發 TypeScript 的過程中,多少都會遇到一個情況:如果有一個 interface 其中之一的屬性是聯集型別,例如 string | number。如果將該 interface 指定給一個物件,且要使用到該屬性時,就會發現只能使用 stringnumber 都共有的屬性。

為了解決這個問題,在 TypeScript 4.9 版的更新中,便引入了 satisfies 來解決型別推導不精確的問題。但既然有了斷言和 Type Guard,又為何需要 satisfies 來解決問題呢?

接下來,就讓我們來看看 satisfies 究竟解決什麼問題,又該如何使用吧!




什麼時候需要用到 satisfies

satisfies 是為了解決在聯合型別或擴展型別的情況下,在不修改變數所屬型別的情況下,靜態推導型別的問題。

satisfies 的使用場景主要集中在以下兩個方面:

  • 不修改原有型別的情況下,確保資料符合特定型別。
  • 進行更細部的靜態型別推導,同時避免引入執行時的負擔。


satisfies 的使用方式

satisfies 的使用方式,其實主要的目的和 interfacetype 的效果接近。

interface Obj1 {
a: number;
b: string;
}

const obj1 = {
a: 1,
b: 2, // Type "number" is not assignable to type "string".
} satisfies Obj1;

接下來,就讓我們透過實際案例,來進一步了解 satisfies 吧!




一、為聯集屬性推定型別

假設有兩種 Task 的形式,一種是 DetailedTask,另一種則是 SimpleTask。當我們生成一個新的 User 物件時,task 的屬性有可能是一個物件或 string。但 TypeScript 沒辦法確認資料有可能是物件還是 string,因此在使用 string 專屬的 charAt 方法時就會報錯。

type SimpleTask = string;

interface DetailedTask {
description: string;
dueDate: Date;
}

type Task = SimpleTask | DetailedTask;

interface User {
name: string;
task: Task;
}

const badUser: User = {
name: "John",
task: "Finish report"
}

badUser.task.charAt() // charAt 會報錯


方案一:透過斷言 as 指定型別

直接透過 as 斷言來確認 badUser 的型別,但帶來的缺點也顯而易見。除了程式碼的易讀性會變低,也會讓程式碼脫離 TypeScript 的型別檢查。因為 as 的目的就是告訴編譯器,不要管我在做什麼,我告訴你這是什麼。

(badUser.task as SimpleTask).charAt(0); // OK


方案二:透過型別謂詞縮減型別

透過型別謂詞來確定型別。透過判別是否為 SimpleTask,讓 TS 知道如何辨別所屬的物件,進而提供可選用的方法。若想進一步了解型別謂詞,可參考 10 分鐘學會 TS 中必會的 5 種型別防禦 Type Guard

function isSimpleTask(task: Task): task is SimpleTask {
return typeof task === "string";
}

if (isSimpleTask(badUser.task)) {
badUser.task.charAt(0); // ok
}


方案三:透過 satisfies 自動推導型別

最後,便是使用 satisfies 來自動推導型別。相較於上面兩個方法,satisfies 能夠自動推導出 badUser.task 屬於 string 型別,因此能夠自動提供 charAt() 的方法。

const goodUser = {
name: "Cat",
task: "Finish the report",
} satisfies User;

goodUser.task.charAt(); // ok

與此同時,當我們滑到 goodUser.task 上時,可以看到編譯器已經幫我們推導出 string 的型別,讓我們能夠自然而然的使用 string 的方法 trim

satisfies type inference

satisfies type inference




二、動態推定擴展型別的資料型別

除了聯集型別可以推定,也可以推定擴展型別,如 [key: string]: any;

TypeScript 僅會提示顯式聲明型別的屬性,但屬於擴展型別範圍的則不會顯示。例如顯式指定了 ab 兩個屬性。

type Obj = {
a: number,
b: string,
[key: string]: any,
}

const objType: Obj = {
a: 1,
b: 2, // 顯示型別錯誤
c: 3, // 不會自動推導
}
raw-image



因為 c 並沒有在 Obj1 中被指定,則在選則 c 屬性時,編譯器並不會有任何提示。可以發現下面的自動補齊完全沒有出現 c



使用 satisfies 後的差異

相反地,使用 satisfies 後,則可以在顯示聲明時檢查顯式聲明 ab,而自動推導 c 的型別。

type Obj = {
a: number,
b: string,
[key: string]: any,
}

const ObjSatisfies = {
a: 1,
b: 2, // 顯示型別錯誤
c: 3, // 自動推導為 number
}
raw-image


可以發現右邊的 obj1. 出現了 c 的自動補齊,代表編譯器有自動推導出 c 的屬性與型別,且 c 的屬性也被正確推導為 number,因而能夠使用 number 特有的屬性。



因此善用 satisfies,可以讓我們在動態推導型別時,能夠兼具程式碼的簡潔,同時也能維護程式碼的型別安全,並讓自動補齊能夠順利做動。


結論與延伸

透過這些例子,我們其實可以發現 TypeScript 其實擁有多種方式可以提升型別安全,但在個別的情境下,又有各自合適的案例。因此當我們需要為一個 typeinterface 檢驗其屬性的型別,屬於聯集型別的哪一種時,就可以使用 satisfies 來達成目的。

如果有任何的筆誤或想法,都歡迎你留言一起討論,讓我們一起深入探索 TypeScript 的強大功能吧!


參考資料 Reference

此處作為整理前端(Frontend)和相關的 HTML、CSS、JavaScript、React 等前端觀念與技巧,全部都會收錄在這個專題之中。同時也會將相關的技術與反思記錄在此,歡迎各位讀者互相交流。
留言0
查看全部
發表第一個留言支持創作者!
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
本文將深入探討鏈表的核心概念,使用 JavaScript 來說明如何實現和操作鏈表(Linked List),包括 append、prepend、remove、find 和 reverse 等五大方法。
「px」,即像素,是最基本的單位,它常被用於指定字體大小、邊框粗細等。「em」和「rem」通常用於調整相對大小,「em」在子元素中的適用,而「rem」則以根元素為參考。另一方面,「vh」和「vw」分別代表視窗的高度和寬度百分比,特別適合實現響應式設計。「vmin」和「vmax」則根據視窗的最小或最大
在 React 測試生態系統中,React Testing Library 成為了方便好用的選擇,因其強調測試應該關注於使用者的操作與觀察元件行為,而不是測試細節實現。
在軟體領域中,"Thunk" 是一個常用的術語,它指的是一種用於延遲計算,或將運算延後執行的程式碼片段。它通常用於函數式編程,或編譯器的設計中。Redux 透過 createAsyncThunk 實作了該非同步/異步操作,並提供數個 API 協助我們使用 Redux。
React 表單驗證是一種技術與使用者體驗的設計,讓使用者能夠即時檢查輸入的資料並修正,提升使用者的使用體驗,並確保資料的正確性。
本文介紹 TypeScript 常遇到的混合型別,以及如何透過五種型別防禦(Type Guard)來解決。涵蓋了使用型別斷言、型別謂詞、in 運算子、typeof 運算子以及 instanceof 運算子這幾種方式。透過本文的學習,能夠更好地運用 TypeScript 進行程式碼開發。
本文將深入探討鏈表的核心概念,使用 JavaScript 來說明如何實現和操作鏈表(Linked List),包括 append、prepend、remove、find 和 reverse 等五大方法。
「px」,即像素,是最基本的單位,它常被用於指定字體大小、邊框粗細等。「em」和「rem」通常用於調整相對大小,「em」在子元素中的適用,而「rem」則以根元素為參考。另一方面,「vh」和「vw」分別代表視窗的高度和寬度百分比,特別適合實現響應式設計。「vmin」和「vmax」則根據視窗的最小或最大
在 React 測試生態系統中,React Testing Library 成為了方便好用的選擇,因其強調測試應該關注於使用者的操作與觀察元件行為,而不是測試細節實現。
在軟體領域中,"Thunk" 是一個常用的術語,它指的是一種用於延遲計算,或將運算延後執行的程式碼片段。它通常用於函數式編程,或編譯器的設計中。Redux 透過 createAsyncThunk 實作了該非同步/異步操作,並提供數個 API 協助我們使用 Redux。
React 表單驗證是一種技術與使用者體驗的設計,讓使用者能夠即時檢查輸入的資料並修正,提升使用者的使用體驗,並確保資料的正確性。
你可能也想看
Google News 追蹤
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
Thumbnail
前言 create react app 是一個可以快速設定 react 專案的一個工具,在建立專案時已經把 babel,webpack 都已經預先封裝設置好,如果我們要修改 webpack alias 設定該如何設定呢 什麼是 alias alias 在 webpack 設定意義叫做,檔案路徑
Thumbnail
當開發大型Web應用時,TypeScript可以提供靜態類型檢查,幫助開發者捕捉潛在的錯誤。結合Gin,你可以建立強大的、類型安全的後端API。
Thumbnail
自己在剛開始進入前端領域時,很剛好遇上需要使用 TypeScript 的案子,一開始都是跟著前輩怎麼寫就怎麼寫,不太有其他餘力來思考「為什麼」會需要寫這門程式語言,直到自己後來使用了 TypeScript 完整開發了電商的購物流程,才慢慢理解到使用 TypeScript 的好處與優勢。
Thumbnail
Todo App是一個很好學習程式語言的專案開始,JayLin來帶大家手把手用TypeScript | React | TailwildCSS 來做一個小專案
Thumbnail
想要知道如何用最新技術來製作一個App嗎? 跟著JayLin用React | Redux Tool Kit | TypeScript | TailwildCSS 來製作一個Drawing App
Thumbnail
Typescript: It's not actually validating your types. - DEV Community 👩‍💻👨‍💻 有時他會讓你誤解: 我遇到一個相信 typescript 保證型別就是你說的那樣. 但我必須告訴你: Typescript 不是這樣做的.
Thumbnail
最近,我看到的關於市場或產品分析的文章,都有著同樣的問題,而這樣的問題,不斷地重複出現在不同作者、不同文章當中,讓我開始懷疑起自己是不是要求太多? 因為,這些文章通常都長篇大論、引經據典,並且詳盡搜集數據進行分析,過程和思路都非常精彩,但是在最後,卻只提出了靠「常識」就能知道的答案。
Thumbnail
這個秋,Chill 嗨嗨!穿搭美美去賞楓,裝備款款去露營⋯⋯你的秋天怎麼過?秋日 To Do List 等你分享! 秋季全站徵文,我們準備了五個創作主題,參賽還有機會獲得「火烤兩用鍋」,一起來看看如何參加吧~
Thumbnail
上一篇文章分享了 TypeScript 的定義、前端角色定位,如果你不是很確定「TypeScript 是什麼?」、「TypeScript 作為 JavaScript 的超集,在網頁開發扮演怎麼樣的角色?」這兩個問題的答案,建議可以回到上一篇先了解一下。
Thumbnail
前言 create react app 是一個可以快速設定 react 專案的一個工具,在建立專案時已經把 babel,webpack 都已經預先封裝設置好,如果我們要修改 webpack alias 設定該如何設定呢 什麼是 alias alias 在 webpack 設定意義叫做,檔案路徑
Thumbnail
當開發大型Web應用時,TypeScript可以提供靜態類型檢查,幫助開發者捕捉潛在的錯誤。結合Gin,你可以建立強大的、類型安全的後端API。
Thumbnail
自己在剛開始進入前端領域時,很剛好遇上需要使用 TypeScript 的案子,一開始都是跟著前輩怎麼寫就怎麼寫,不太有其他餘力來思考「為什麼」會需要寫這門程式語言,直到自己後來使用了 TypeScript 完整開發了電商的購物流程,才慢慢理解到使用 TypeScript 的好處與優勢。
Thumbnail
Todo App是一個很好學習程式語言的專案開始,JayLin來帶大家手把手用TypeScript | React | TailwildCSS 來做一個小專案
Thumbnail
想要知道如何用最新技術來製作一個App嗎? 跟著JayLin用React | Redux Tool Kit | TypeScript | TailwildCSS 來製作一個Drawing App
Thumbnail
Typescript: It's not actually validating your types. - DEV Community 👩‍💻👨‍💻 有時他會讓你誤解: 我遇到一個相信 typescript 保證型別就是你說的那樣. 但我必須告訴你: Typescript 不是這樣做的.
Thumbnail
最近,我看到的關於市場或產品分析的文章,都有著同樣的問題,而這樣的問題,不斷地重複出現在不同作者、不同文章當中,讓我開始懷疑起自己是不是要求太多? 因為,這些文章通常都長篇大論、引經據典,並且詳盡搜集數據進行分析,過程和思路都非常精彩,但是在最後,卻只提出了靠「常識」就能知道的答案。