我承認,我不太懂 TypeScript

有一天,我在一些處理樂觀更新的程式碼中遇到了一個錯誤,所以我向我的同事Filip尋求幫助。 TypeScript 精靈 Filip 提到satisfies關鍵字將是我正在尋找的解決方案的一部分。

Satisfies ?那是什麼呀?為什麼我以前從未聽說過它?我的意思是,我已經使用 TypeScript 一段時間了,所以我很驚訝我自己並不了解它。

圖片描述

不久之後,我偶然發現了 @yacineMTB 的這條推文,他是X.com (又名 Twitter)的多產者和工程師:

就像,為什麼我不能只*執行*打字稿檔案?如果我需要初始化整個目錄和專案,那麼腳本語言有什麼意義呢?

我再次發現自己想知道為什麼我還不了解 TypeScript。為什麼你不能真正執行 TypeScript 檔案?腳本語言和編譯語言有什麼不同?

圖片描述

我突然意識到,我不太了解我幾乎每天使用的語言的一些基本知識,這些語言是我用來建立諸如Open SaaS (一個免費的開源 SaaS 入門工具)之類的東西的。

所以我決定退一步,對這些主題進行一些調查。在這篇文章中,我將與您分享我學到的一些最重要的事情。

TypeScript 是什麼類型的腳本?

您可能已經聽說過 TypeScript 是 JavaScript 的「超集」。這意味著它是 JavaScript 之上的一個附加層,在本例中,它允許您向 JavaScript 加入靜態類型。

圖片描述

這有點像 TypeScript 是 JavaScript 的進階版。或者,換句話說,如果 JavaScript 是 Tesla Model 3 的基礎模型,那麼 TypeScript 就是 Model X Plaid。嗚嗚嗚。

但因為它是 JavaScript 的超集,所以它實際上並不像 JavaScript 本身那樣運作。例如,JavaScript 是一種腳本語言,這意味著程式碼在執行過程中會被逐行解釋。它被設計成可以在不同作業系統和硬體配置的網路瀏覽器中運作。這與 C 等低階語言不同,後者需要先編譯為特定係統的機器碼才能執行。

圖片描述

因此,JavaScript 不必先編譯,而是由 JavaScript 引擎解釋。另一方面,TypeScript 必須先轉換(或「轉編譯」)為 JavaScript,然後才能由瀏覽器中的 JavaScript 引擎(或作為獨立的 NodeJS 應用程式)執行。

所以這個過程看起來有點像這樣:

 → Write TypeScript Code

    → “Transcompile” to JavaScript

      → Interpret JavaScript & Check for Errors

        → JavaScript Engine Compiles and Executes the Code

很有趣,對吧?

現在我們已經掌握了一些理論知識,接下來讓我們繼續討論一些更實際的東西,例如 TypeScript 的出名之處:它就是類型!


順便一提…

我們Wasp正在努力建立最好的開源 React/NodeJS 框架,讓您快速行動!

這就是為什麼我們提供了即用型全端應用程式模板,例如帶有 TypeScript 的 ToDo 應用程式。您所要做的就是安裝 Wasp:

curl -sSL https://get.wasp-lang.dev/installer.sh | sh

並執行:

wasp new -t todo-ts

圖片描述

您將獲得一個開箱即用的具有 Auth 和端到端 TypeSafety 功能的全端 ToDo 應用程式,以幫助您學習 TypeScript,或者只是開始快速安全地建置一些東西:)


玩耍satisfies

還記得我如何向我的同事尋求幫助,他的解決方案涉及satisfies關鍵字嗎?好吧,為了更好地理解它,我決定打開一個編輯器並嘗試一些基本範例,這是我發現的最有用的東西。

首先,我們以 person 物件為例,將其輸入為Record ,該 Record 可以採用一組PossibleKeys和一個stringnumber作為值。那想看看這個:

type PossibleKeys = "id" | "name" | "email" | "age";

const person: Record<PossibleKeys, string | number> = { } 

我們輸入person常數的方式稱為型別註解。它直接位於變數名稱之後。

讓我們開始為此person物件新增鍵和值:

type PossibleKeys = "id" | "name" | "email" | "age";

const person: Record<PossibleKeys, string | number> = {
  id: 12,
  name: "Vinny",
  email: "[email protected]",
  age: 37,
} 

看起來很簡單,對吧?

現在,讓我們來看看 TypeScript 如何推斷person屬性的類型:

圖片描述

有趣的。當我們將滑鼠懸停在email上時,我們看到 TypeScript 告訴我們電子郵件是stringnumber的聯合類型,即使我們肯定只將其定義為string

如果我們嘗試在這種類型上使用一些string方法,這將會產生一些意想不到的後果。讓我們嘗試一下split方法,例如:

圖片描述

我們收到一個錯誤,表示此方法不適用於number類型。哪個是對的。但這很煩人,因為我們知道email是一個字串。

satisfies透過將類型向下移動到常數定義的末尾來解決這個問題:

type PossibleKeys = "id" | "name" | "email" | "age";

const person = {
  id: 12,
  name: "Vinny",
  email: "[email protected]",
  age: 37,
} satisfies Record<PossibleKeys, string | number>;

現在,當將滑鼠懸停在email屬性上時,我們將看到它被正確推斷為string

圖片描述

好的!現在,我們使用splitemail轉換為字串陣列不會遇到任何問題。

這就是satisfies真正的閃光點。它讓我們驗證表達式的類型是否與特定類型匹配,同時為我們推斷最窄的可能類型。

多餘的財產檢查

但當我玩satisfies時,我注意到另一個奇怪的事情是,如果我直接在變數上使用它與在中間變數上使用它,它的行為會有所不同,如下所示:

// Directly on object literal
const person = { } satisfies PersonType;

// Using on intermediate variable
const personIntermediate = person satisfies PersonType

具體來說,如果我向person物件加入類型中不存在的另一個屬性(例如isAdmin ,則直接使用時我們會收到錯誤,但使用中間變數時不會收到錯誤:

  1. 直接使用satisfies

圖片描述

  1. 使用satisfies和中間變數

圖片描述

您可以看到,在範例 2 中,沒有錯誤且 person “滿足” PersonType ,但在範例 1 中卻沒有。

這是為什麼?

嗯,這實際上與 JavaScript 的基本工作原理有關,而與satisfies關鍵字關係不大。讓我們來看看。

上面範例中發生的過程就是所謂的「多餘屬性檢查」。

過多的屬性檢查實際上是該規則的例外。 TypeScript 使用所謂的「結構類型系統」。這只是一種奇特的方式來表示如果一個值具有所有預期的屬性,那麼它將被使用。

因此,使用上面的personIntermediate範例,TypeScript 不會抱怨person有一個額外的屬性isAdmin ,該屬性在PersonType中不存在。它具有所有其他必要的屬性,例如idnameemailage ,因此 TypeScript 接受這種中間形式。

但是,當我們直接在變數上聲明類型時(如範例 1 中所示),我們會收到 TypeScript 錯誤:「'isAdmin' 在類型 'PersonType' 中不存在」。這是工作中的多餘屬性檢查,它可以幫助您避免犯下愚蠢的錯誤。

記住這一點是有好處的,因為這將幫助您避免意外的副作用。

例如,假設我們將 person 類型變更為具有可選的isAdmin屬性,如下所示:

type PersonType = {
  id: number,
  name: string,
  isAdmin?: boolean, // 👈 Optional
}

如果我們不小心用isadmin屬性而不是isAdmin定義了person並且沒有直接聲明類型,會發生什麼情況?

我們不會從 TypeScript 中得到任何錯誤,因為person實際上滿足所有必要的類型。 isAdmin類型是可選的,它不存在於person上,但這並不重要。您已經做了一個簡單的 type-o,現在嘗試存取isAdmin屬性,但它不起作用:

圖片描述

哎呀!讓我們用類型註釋來修復它,我們立即聲明類型:

圖片描述

好的。因為我們在第 58 行使用了直接類型註釋,所以我們獲得了 TypeScript 多餘屬性檢查的好處。

謝謝,打字稿! 🙏


如果您發現此內容有用,並且想要查看更多類似內容,您可以在 GitHub 上給 Wasp 一顆星,輕鬆幫助我們!

https://dev-to-uploads.s3.amazonaws.com/uploads/articles/qgbmn45pia04bxt6zf83.gif

{% cta https://www.github.com/wasp-lang/wasp %} ⭐️ GitHub 上的 Star Wasp 🙏 {% endcta %}


待續…

感謝您加入我的旅程的第 1 部分,以便更好地了解我們每天使用的工具。

這將是一個持續進行的系列,我將繼續以更具探索性、更少結構化的方式分享我所學到的東西。我希望您發現其中的某些部分有用或有趣。

讓我知道你接下來想看什麼!你喜歡這種風格嗎?你願意改變一些事情嗎?加入或刪除一些東西?或者你對最近學到的東西有什麼看法或類似的故事嗎?

如果是這樣,請在評論中告訴我們,我們下次見:)


原文出處:https://dev.to/wasp/ive-been-writing-typescript-without-understanding-it-5ef4


共有 0 則留言