<?xml version="1.0" encoding="UTF-8"?>
<rss version="2.0" xmlns:atom="http://www.w3.org/2005/Atom" xmlns:dc="http://purl.org/dc/elements/1.1/">
  <channel>
    <title>DEV Community: Angus</title>
    <description>The latest articles on DEV Community by Angus (@angushyx).</description>
    <link>https://dev.to/angushyx</link>
    <image>
      <url>https://media2.dev.to/dynamic/image/width=90,height=90,fit=cover,gravity=auto,format=auto/https:%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Fuser%2Fprofile_image%2F920183%2F420ba807-9211-4a94-b6bc-fb926f478c13.jpeg</url>
      <title>DEV Community: Angus</title>
      <link>https://dev.to/angushyx</link>
    </image>
    <atom:link rel="self" type="application/rss+xml" href="https://dev.to/feed/angushyx"/>
    <language>en</language>
    <item>
      <title>淺談即時通訊系統以及Socket.io、Socket、WebSocket 差異</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Wed, 30 Nov 2022 07:31:02 +0000</pubDate>
      <link>https://dev.to/angushyx/socketio-socket-websocket-chai-yi-602</link>
      <guid>https://dev.to/angushyx/socketio-socket-websocket-chai-yi-602</guid>
      <description>&lt;p&gt;先前的專案中使用過 socket.io 實做聊天室功能，當初的概念只有 1. 事件驅動 2. HTTP之外的通訊協議 3. 即時互動，今天就來詳細了解 Websocket 與 HTTP 和網路是什麼關係、最後再來比較 socket.io 與 WebSocket 以及 socket 之間的差別。&lt;/p&gt;

&lt;p&gt;在比較三者之間的差別之前必須要先理解為什麼我們不 HTTP 與 Websocket 之間的差別。&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  從 HTTP 來比對即時通訊系統
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;傳統的瀏覽器以及 HTTP 早期只能夠從 client 端主動發出請求接著 server 端回應並回覆請求來實現資料互動，不過有許多像是監控、即時線上通訊、即時報價等情境，需要的是將後台發生的變化&lt;strong&gt;主動、即時的&lt;/strong&gt;傳到瀏覽器端，而不是等待用戶手動更新頁面，也因此應運而生了許多方案。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;輪詢 ( polling )：最簡單的方案。用戶端定期發送 AJAX 請求，伺服器再收到請求之後立刻回傳資料。雖然確保了資料的相對即時性也具有良好的瀏覽器相容性也很簡單。不過輪詢的頻率是最致命的缺點，舉例來說：當輪詢頻率太高時，就會產生大量無效請求; 過低時資料的即時性變差，同時，伺服器端壓力變大，進而浪費頻寬流量。&lt;/p&gt;

&lt;p&gt;function polling() {&lt;br&gt;
  console.log("polling");&lt;br&gt;
}&lt;br&gt;
setInterval(shortPolling, 1000);&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;長輪詢(long-polling) ：可想成輪詢的優化版本：用戶端透過 AJAX 發起請 求，伺服器端再接到請求後不馬上回傳，而是保持連接，等待資料更新。一旦有資料需要發送給用戶端時，伺服器端才將目標資料發送給用戶端，傳回請求。用戶端收到回應之後，馬上再發起一個新的請求給伺服器端，持續循環。&lt;/li&gt;
&lt;/ol&gt;


&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;雖然能夠有效減少輪詢的次數以及大幅降低延遲，但伺服器需要保持大量的連結，也是會產生一定的消耗。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--4inB9Tua--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A7bJdafKX_80jM6Di7au2vQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--4inB9Tua--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A7bJdafKX_80jM6Di7au2vQ.png" alt="圖一、[polling 與 long-polling 差異](https://codeburst.io/polling-vs-sse-vs-websocket-how-to-choose-the-right-one-1859e4e13bd9)" width="880" height="432"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;function longPolling() {
  setTimeout(function() {
    console.log("Long Polling");
    longPolling();
  }, 1000);
}
longPolling();
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;
&lt;p&gt;Comet streaming ：此技術又被稱作 Forever iframe，需要我們動態載入一個隱藏的 iframe 標籤， iframe 標籤的 src 會指向請求的伺服器位址。同時 client 端會準備好一個處理資料的函式，在伺服器端透過 iframe 標和用戶端通訊時，伺服器端便會傳回 script 標籤的文字，用戶端會將其解析為 JavaScript 指令稿，並呼叫預先準備好的函數，將資料傳遞給 parant window，類似 JSONP 的實現原理，程式如下。&lt;/p&gt;

&lt;p&gt;parant.getData("data from server")&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;JAX multipart streaming：使用到了 HTTP 1.1 中的 multipart 特性：client 發送請求，server 保持連接，再利用 HTTP 1.1 的 chunked encoding 機制 (分段傳輸編碼 ) 將資料傳遞給用戶端，直到逾時或 client 端手動中斷才停止傳輸。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;乍看之下與 WebSocket 功能似乎相同不過由於 HTTP 1.1 中的 multipart 特性並沒有被瀏覽器廣泛支援，此方法並不常見。&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;WebScoket：是從 HTML 5 開始提供的一種在瀏覽器與伺服器間進行全雙工通訊的網路技術。依靠此技術可以實現 client 端與 server 端的長連接，達到雙向即時通訊的效果。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--dPExKpGr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3162/1%2A1gjGSrruW2ipiVRbNPDB9A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--dPExKpGr--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3162/1%2A1gjGSrruW2ipiVRbNPDB9A.png" alt="圖二、[WebSocket 與long-polling ](https://ably.com/blog/websockets-vs-long-polling)差異" width="880" height="404"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;從 HTTP 與 WebSocket 的關係 ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在&lt;a href="https://medium.com/@sickmi14798/d040d8d581e6"&gt;網路七層架構&lt;/a&gt;( 日後再寫 )中，HTTP 與 WebSocket 都屬於第七層的應用層協定，且都是以 TCP 為基礎來傳輸資料。 WebSocket 依賴一種升級的 HTTP 進行一次驗證，驗證成功之後資料即可在 TCP 通道中進行傳輸了。&lt;/p&gt;

&lt;p&gt;如此一來，&lt;strong&gt;連接的發起端始終是 clinet 端&lt;/strong&gt;，不過一旦WebSocket 連接建立之後，不論是 clinet 端還是 server 端都可以向對方發送資料。&lt;/p&gt;

&lt;p&gt;即使 WebSocket 強大，還是錯過了瀏覽器為 HTTP 提供的一些服務，這些服務就需要開發者自行實現，因此 WebSocket 暫時還無法取代 HTTP 。&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  Socket.io、Socket、WebSocket 差異
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;講了這麼多終於談到今天的主題了，在進入主題之前TCP/IP 的四個層級介紹可以更了解三者之間的關係。&lt;/p&gt;

&lt;p&gt;TCP/IP 的四個層級介紹：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;應用層 (Application Layer)：網路模型的最上層，也是想要利用網路傳輸資料的程式，能夠直接碰觸到的層級。EX： telnet、FTP、WWW、Email、DNS、socket.io、HTTP、WebSocket、engine.io&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;傳輸層 (Transport Layer)：此層對應用層傳送過來的資料進行處理，建立2台電腦之間可靠的傳輸，在此層常見的2種協定為TCP與UDP。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;網路層 (IP Network Layer)：網路層能夠提供實體介面網路卡一個邏輯上的位置，也就是我們常聽到的IP位址。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;鏈接層 (Network Access Layer)：位於整個網路架構的最底層，負責制定資料傳輸的「實體」規格 ，EX：乙太網路的規格等。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Q7vxH286--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aw2_5VJ3fSyydVd_0CF9Daw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Q7vxH286--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aw2_5VJ3fSyydVd_0CF9Daw.png" alt="圖三、四層架構" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Socket 是甚麼 ? 它在哪裡 ?
&lt;/h2&gt;

&lt;p&gt;Socket是應用層與TCP/IP協議通信的中間軟體抽象層，它是&lt;strong&gt;一組介面 ( *&lt;em&gt;Socket Interface *&lt;/em&gt;)&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;在設計模式中， Socket其實就是一個門面模式，它&lt;strong&gt;把複雜的TCP/IP協議隱藏在Socket介面後面，&lt;/strong&gt;對用戶來說，一組簡單的介面就是全部，讓Socket去組織數據。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5CSg3Iao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ag_U7H2ZOnZtcdnW4P_23Vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5CSg3Iao--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ag_U7H2ZOnZtcdnW4P_23Vw.png" alt="圖三、socket 位於*傳輸層跟應用層之間*" width="880" height="880"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;介紹完 socket 後相信讀者對於應用層中的 Socket.io 與 Websocket 又更好奇了&lt;/p&gt;

&lt;h2&gt;
  
  
  WebSocket
&lt;/h2&gt;

&lt;p&gt;WebSocket 顧名思義，就是為了提升 web 通訊速度而被創造出來的一種&lt;strong&gt;「協議」，&lt;/strong&gt;它的原理是在瀏覽器底層以剛剛提到的「socket」當作&lt;strong&gt;通訊介面&lt;/strong&gt;，通訊協議才是採用它自身的「Websocket協議」。&lt;/p&gt;

&lt;p&gt;可以想成&lt;strong&gt;協議與介面&lt;/strong&gt;都裝在瀏覽器上，因此只要瀏覽器支援，就可以使用這個協議透過web來跟伺服器做溝通。&lt;/p&gt;

&lt;h3&gt;
  
  
  WebSocket 與 HTTP 的關係
&lt;/h3&gt;

&lt;p&gt;我們都清楚要和 server 溝通需要通過 HandShaking ，Websocket 也不例外，而第一次 HandShaking 則是使用&lt;strong&gt;「HTTP協議」&lt;/strong&gt;接下來 HTTP協議就不會再用到囉，而是使用 Websocket 協議。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--t0Gzo8uH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AjRFxDJr88he3ZXNcJQLRMw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--t0Gzo8uH--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AjRFxDJr88he3ZXNcJQLRMw.png" alt="" width="880" height="482"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  socket.io &amp;amp;&amp;amp; engin.io
&lt;/h2&gt;

&lt;p&gt;那大家最熟悉的 socket.io 又是甚麼呢 ? 解決了甚麼問題呢 ?&lt;/p&gt;

&lt;p&gt;與 WebScoket 一樣 socket.io 也是為了解決 web 即時通訊而誕生的，不一樣的是 &lt;strong&gt;socket.io 是一個框架而不是協議。&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;上面有提到要在瀏覽器有支援的前提之下才能使用 WebSocket ，那如果瀏覽器不支援，而程式裡使用了 WebSocket 的技術時怎麼辦呢 ??&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;socket.io 解決了這個問題，在大部分情況之下 WebSocket 與 socket.io都是使用 WebSocket 協議做即時的通訊，不過當遇到上述情境時，&lt;strong&gt;socket.io會改選擇使用傳統的 long-polling ( 長輪詢 ) 方式運作&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;沒錯!! 就是一開始介紹的那種即時通訊方式。&lt;/p&gt;

&lt;p&gt;不過 socket.io 僅僅是在上層做一些介面封裝，真正連線的角色是 &lt;strong&gt;engin.io&lt;/strong&gt; 舉凡通訊相關，連接等等，都是engine.io在實現。&lt;/p&gt;

&lt;p&gt;小結：講了這麼多，最後用個表格來簡單區分 WebSocket 與 Socket.io 的主要差別。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rxOZ_Hls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-3z0fIMFW3MG7GCtWhB3KQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rxOZ_Hls--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-3z0fIMFW3MG7GCtWhB3KQ.png" alt="" width="880" height="1056"&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>webrtc</category>
      <category>javascript</category>
      <category>webscoket</category>
    </item>
    <item>
      <title>【TypeScript 30】Day 5：陣列與元組 ( Tuple )</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Fri, 25 Nov 2022 05:01:36 +0000</pubDate>
      <link>https://dev.to/angushyx/typescript-30-day-5zhen-lie-yu-yuan-zu-tuple--306c</link>
      <guid>https://dev.to/angushyx/typescript-30-day-5zhen-lie-yu-yuan-zu-tuple--306c</guid>
      <description>&lt;p&gt;經過前幾天的分享，已經大致上介紹完了大部分基本物件的型別推論跟註記的機制囉!!&lt;/p&gt;

&lt;p&gt;緊接著就繼續介紹 TypeScript 有而 JavaScript 沒有的資料型別吧!!&lt;/p&gt;

&lt;h3&gt;
  
  
  元組( Tuple ) 以及列舉 ( Enums )
&lt;/h3&gt;

&lt;p&gt;元組其實與陣列很像，所以在這裡我們先來比較一下兩者的區別，既然要比較那就一樣從型別推論與定義開始吧!!&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;元組 ( Tuple ) 的定義與型別推論&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;當元組值被指派到變數時，&lt;strong&gt;一定得進行積極型別註記。&lt;/strong&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;在這裡舉個例子：若想存取各種調酒的資訊，以 JS 陣列格式存取 — 第一個值為基酒名稱，酒精濃度，添加香料，基酒年分別。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0Auzd5aW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2680/1%2AD0YQGeI6tFm9gwqPiWGAZg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0Auzd5aW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2680/1%2AD0YQGeI6tFm9gwqPiWGAZg.png" alt="圖一" width="880" height="290"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;依造前一篇提到的 union 的觀念我們預期推斷出來的型別會是 (string | number | Date)[] ，在這種情況下我們無法得知陣列中各索引所對應的型別，因此我們在這裡我們使用 TS 的&lt;strong&gt;元組型別&lt;/strong&gt;，會像下圖這樣。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--uhT6Acyl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2Aht2TKFO6psJ-d-HMEVaScg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--uhT6Acyl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2560/1%2Aht2TKFO6psJ-d-HMEVaScg.png" alt="圖二" width="880" height="696"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在這裡讀者就會想到[string, number, string, Date]這段註記型別的程式碼重複性很高，肯定有優化的空間，有的!! 那就是 — — &lt;strong&gt;型別化名（Type Alias）&lt;/strong&gt;。&lt;/p&gt;

&lt;p&gt;型別化名的規則如下&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;type &amp;lt;custom-type-name&amp;gt; = &amp;lt;your-type&amp;gt;;
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;不過在每個同樣類型的陣列重複了相同的程式碼一定會有優化的空間，在這裡，使用型別化名我們只需要標示一次此陣列的型別，接下來使用定義好的化名就可以省略一長串的元組型別格式了，&lt;strong&gt;稱為 — *抽象化(Abstraction)&lt;/strong&gt;*&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0DlpEb9f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2208/1%2AtlDB4kWO-wqd1bYshZRlKg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0DlpEb9f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2208/1%2AtlDB4kWO-wqd1bYshZRlKg.png" alt="圖三" width="880" height="625"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那麼使用元組對我們開發上有什麼實質上的幫助呢?&lt;/p&gt;

&lt;p&gt;在回答這個問題之前要先曉得元組與陣列的差異，相信看過剛剛的型別註記後就能看出差別，以調酒資料為例：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--BaHEf8lE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2AzBfXU3lDxFd6W58iUR0w3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--BaHEf8lE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2AzBfXU3lDxFd6W58iUR0w3w.png" alt="圖四、陣列與元組差別" width="880" height="340"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;重點陣列型別中，只要裡面的元素為此陣列規定的範疇，就不會出錯，也就是說陣列中的元素型只要是 string 、 number 、 Date 就不會出問題，元素的數量、順序都不被列入規定範疇 ; 反之，使用元組不僅型別必須符合規定外，順序、數量都必須按造元組的規定。&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;看看例子吧：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--V9g2byLg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2056/1%2A4TJcGDn7xDj1i0KLO2t40Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--V9g2byLg--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2056/1%2A4TJcGDn7xDj1i0KLO2t40Q.png" alt="圖五" width="880" height="1257"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如此一來就可以比較準確的推斷該陣列中的各個型別&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--h50IcSrs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AUo6M_BGm7JN1aPDMz60-7g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--h50IcSrs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AUo6M_BGm7JN1aPDMz60-7g.png" alt="圖六" width="880" height="435"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不過讀者可能又會想說，如果資料型別相同的話不也一樣可能誤解元素的意義嗎 ? 拿剛剛的例子來說：&lt;/p&gt;

&lt;p&gt;同為字串類型的基酒( index 0 ) ，和香料(idnex 2 ) ，如果反過來的話並不會出錯，原本的意思是 ：Manhattan 的基本資料：&lt;strong&gt;基酒為 whisky **，酒精濃度 30%，&lt;/strong&gt;添加香料使用 "Angostura"**，基酒出產日期為 2005/02/03。&lt;/p&gt;

&lt;p&gt;不過因為調換字串類型 typeScript 無法幫我們判別基酒與香料的差別，因此當調換時變成基酒是 &lt;strong&gt;“Angostura” ，香料為 whisky。&lt;/strong&gt;這就完全不符合我們的預期了，因此建議使用元組定義型別時，建議使用 Josn 格式定義，如下：&lt;/p&gt;

&lt;p&gt;如此一來不僅解決了&lt;strong&gt;順序差異的問題之外更增加了描述性。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3hIP0TYW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2A6TERhRcyBikTWOcyXuyu-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3hIP0TYW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2092/1%2A6TERhRcyBikTWOcyXuyu-Q.png" alt="圖七、使用JSON格式撰寫元組" width="880" height="724"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;小結：這幾天忙著面試，原本預計這篇文章要在 2 天前完成的，拖了幾天比較有時間完成，接著下來要介紹的是 TypeScript 另一個自定義型別 ( Enum )&lt;/p&gt;

</description>
    </item>
    <item>
      <title>【TypeScript 30】Day 4：陣列型別</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Fri, 25 Nov 2022 05:00:33 +0000</pubDate>
      <link>https://dev.to/angushyx/typescript-30-day-4zhen-lie-xing-bie-o77</link>
      <guid>https://dev.to/angushyx/typescript-30-day-4zhen-lie-xing-bie-o77</guid>
      <description>&lt;p&gt;前幾天討論完了物件型別中的函式型別與基本物件型別後，接著來聊聊同樣隸屬於物件型別中的陣列型別吧!&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  物件型別之陣列型別
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;h2&gt;
  
  
  陣列的推論
&lt;/h2&gt;

&lt;p&gt;同樣的先從最基礎的型別推論開始看起，一個是全是 number 類型的陣列另一個則全都是 string 類型的陣列。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yWlnBU1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2112/1%2A79sJWOLCTMFxiNqwMvNnow.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yWlnBU1j--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2112/1%2A79sJWOLCTMFxiNqwMvNnow.png" alt="圖一" width="880" height="368"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;陣列型別的註記方式也非常的直覺，在一個陣列中如果型別都相同會直接使用該陣列裡值的型別加上 " [] " ，直接告訴你這是一個 number 或 string 類型的陣列。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--54aPD2Yw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Am5c0ckHD9ZYzJUICGduC_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--54aPD2Yw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Am5c0ckHD9ZYzJUICGduC_w.png" alt="圖二、陣列中的值全都是數字類型" width="717" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--_GtrOunh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-Jsfcy_yk6aIvaPqoaFlcg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--_GtrOunh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-Jsfcy_yk6aIvaPqoaFlcg.png" alt="圖三、陣列中的值全都是字串類型" width="743" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;既然都已經將 number 、string 這兩個陣列推論完類型了，按造前面兩篇文章的邏輯來操作陣列中的元素看看會發生什麼事。&lt;/p&gt;

&lt;p&gt;完全符合我們的預期，一旦 number 已經被定義為 number[]類型後接下來再想要修改、新增元素到陣列中一定要是 number 類型。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xisymF3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ADOIGp0uKsi4QhOfz2mG7BQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xisymF3k--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ADOIGp0uKsi4QhOfz2mG7BQ.png" alt="圖四、Homogeneous Type Array — 同質性陣列" width="809" height="312"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;混合類型陣列&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;再推論混合類型時，TS 很聰明使用了 union 來推論出陣列中所有的類型。&lt;/p&gt;

&lt;p&gt;union 類似於 or 結合因此在這個陣列中可以存在的類型包括 ，string 、number、boolean以及一個 string 類型的物件。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xbax7Uam--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AEIzw9KZMX98eJ4xmed8dVA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xbax7Uam--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AEIzw9KZMX98eJ4xmed8dVA.png" alt="圖五、Heterogenous Type Array — 異質性陣列" width="743" height="128"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;覆寫陣列中的物件&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在 &lt;a href="https://medium.com/@sickmi14798/typescript-30-day-2-%E7%89%A9%E4%BB%B6%E5%9E%8B%E5%88%A5-8960b933d761"&gt;Day2 — 物件型別&lt;/a&gt; 中提到複寫物件型別的雷點，接著我們就來測試看看在陣列裡的物件型別是不是有相同的問題，如下。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QfjKmvGh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AlaaUNLpYcX7IrfoS_WeIPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QfjKmvGh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AlaaUNLpYcX7IrfoS_WeIPg.png" alt="圖六、三種不同的物件陣列" width="880" height="644"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;下面一一列出推論出的型別。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--lMQGYZoB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_bjcgi6VRPYMa6s2B_oUtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--lMQGYZoB--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_bjcgi6VRPYMa6s2B_oUtQ.png" alt="圖七、毫無懸念推論出的型別是 { name:string }[]" width="648" height="133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s32Q792f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A53mDjRzFxpQG5B_WFgTmIw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s32Q792f--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A53mDjRzFxpQG5B_WFgTmIw.png" alt="圖八、推論出 { name:string; isCrazy?:undefined } | { name: string ; isCrazy:boolean }[]" width="691" height="306"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IdVuQMbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AQ1Y9GScxhCnaUQ8epQvaYA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IdVuQMbf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AQ1Y9GScxhCnaUQ8epQvaYA.png" alt="圖九、兩種型別使用 union 推論出 { name: string;} | { name: number;})[]" width="657" height="178"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;圖七與圖九都在我們目前的理解範圍之內，圖八實際上要表示的意思其實就等同於&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;({ name: string; isCrazy?: boolean; }
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;不過這裡卻推論為，這裡與屬於後面文章的範疇，目前先擱著。&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const objArr2: (
{ name: string; isCrazy?: undefined;} | { name: string; isCrazy: boolean;})[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;blockquote&gt;
&lt;p&gt;重點：假設 SET 為陣列中所有元素的集合，*&lt;em&gt;在大部分的情況之下 ( 好奇有哪種情況不會 ) *&lt;/em&gt;該陣列被 TypeScript 型別推論的結果為 ：&lt;/p&gt;
&lt;/blockquote&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(集合 SET 中所有 `union` 的結果) []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;可能有點難理解那就來看看例子吧!!&lt;/p&gt;

&lt;p&gt;圖十是兩種不同型別的函式所組成的陣列，依造上面公式預期得到 string 和 number類型的 function。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--jsO_CjTw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AaUGsCPQt7iUv1HP0PJWv_w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--jsO_CjTw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AaUGsCPQt7iUv1HP0PJWv_w.png" alt="圖十之一" width="880" height="562"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;推論出的類型是，與上述的公式相符。&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const set1: (((num1: number, num2: number) =&amp;gt; number) | ((str1: string, str2: string) =&amp;gt; string))[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--YG-rTPlC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AZWcwd-jCbd8cYW9-fJ2mAg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--YG-rTPlC--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AZWcwd-jCbd8cYW9-fJ2mAg.png" alt="圖十之二" width="714" height="296"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那接下來檢查看看相同 I/O 的 function 吧&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--kst5mL3M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AmoX5tm-4nQwIbu0OEV9h2w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--kst5mL3M--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AmoX5tm-4nQwIbu0OEV9h2w.png" alt="圖十一之一、 I/O的類別都是 number" width="880" height="535"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;因為結果都一樣，因此推論出了：&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const set2: ((num1: number, num2: number) =&amp;gt; number)[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IBMhmBCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ampfsli_OTQJtQ3DTqf7pww.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IBMhmBCW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ampfsli_OTQJtQ3DTqf7pww.png" alt="圖十一之二、 I/O的類別都是 number" width="700" height="256"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;再來試試稍微更複雜一點的 array 包著 array 的三個例子：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;第二層陣列中的元素只包含 string、number、boolean*&lt;em&gt;此類的原始型別 ( Primitive Types)&lt;/em&gt;* 。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ss2vlhov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AEdydEBwsNIK_njlXwTcWlw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ss2vlhov--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AEdydEBwsNIK_njlXwTcWlw.png" alt="圖十二之一" width="880" height="426"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;第一種情況很單純也很簡潔得到了&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const complexArr1: (string | number | boolean)[][]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xjVjAN5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A7g6k_a7LX98Mac4BHtpjfQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xjVjAN5Q--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A7g6k_a7LX98Mac4BHtpjfQ.png" alt="圖十二之二" width="658" height="162"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;第二層陣列中的元素只除了&lt;strong&gt;原始型別 ( Primitive Types)&lt;/strong&gt; ，還有&lt;strong&gt;物件型別 (Object Types)&lt;/strong&gt;。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ujITXzq6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AYSTaxllZ9KZmhwZ7Zh1thw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ujITXzq6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AYSTaxllZ9KZmhwZ7Zh1thw.png" alt="圖十三之一" width="880" height="398"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如果陣列中有包含&lt;strong&gt;物件型別&lt;/strong&gt;的話，則會將有物件型別的陣列(此範例是 [1, 2 , ’3’, { obj:1 } ] ) 另外歸類為&lt;strong&gt;另一種型別的組合，&lt;/strong&gt;如下圖。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--GhAaErf8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-fd3O0MsAnD45ul7lnWamg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--GhAaErf8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A-fd3O0MsAnD45ul7lnWamg.png" alt="圖十三之二" width="772" height="230"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;另外被分類的組合如下：&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;(string | number | { obj: number;})[]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;ol&gt;
&lt;li&gt;第二層陣列中的元素只除了&lt;strong&gt;原始型別 ( Primitive Types)&lt;/strong&gt; ，物件型別還有 nullable type。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hUOJQIpF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AgRHrSTJnDOwG4mcCrfyJnA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hUOJQIpF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2456/1%2AgRHrSTJnDOwG4mcCrfyJnA.png" alt="圖十四之一" width="880" height="453"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;和物件型別類似的概念，有包含 nullable type 的陣列也都被獨立出一個組合。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--0_BW8Lf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ArtO5kR_fGYx5vOn1sjp00g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--0_BW8Lf_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ArtO5kR_fGYx5vOn1sjp00g.png" alt="圖十四之二" width="779" height="320"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  陣列的註記
&lt;/h2&gt;

&lt;p&gt;看完推論後接著就來看看註記吧，不過看完上面的推論過後，註記應該就沒有甚麼太大的問題了。&lt;/p&gt;

&lt;p&gt;宣告一個空陣列，如果看過前兩篇文章的讀者應該不難猜到這裡的型別會被推論為 any []&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let emptyArr = []
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rrwkdqch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aj10fhcLlZTPxl8fZjialTw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rrwkdqch--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aj10fhcLlZTPxl8fZjialTw.png" alt="圖十五、沒有註記型別推論為 any (error 是 eslint 的 config)" width="699" height="210"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;這是一種我們會想對陣列做積極註記的一種情況，而還有另一種情況你會想要對陣列做型別註記，那就是 — — 如果目前陣列的型別中，&lt;em&gt;沒有出現你需要的型別值&lt;/em&gt;，你必須得對該陣列積極作型別備註。&lt;/p&gt;

&lt;p&gt;什麼意思呢 ? 假設我們想讓下面這個陣列同時包含 string 和 nullable type 時&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const stringAndNull = [‘hello’, ‘angus’]
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;此時的 stringAndNull 此時的已經被推論為 string [] ，所以我們如果向以下程式碼推入 null，進入這個陣列一定會出錯。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--azf_TjqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AKx6dA-fOA4Dte2_G8Il6XQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--azf_TjqT--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AKx6dA-fOA4Dte2_G8Il6XQ.png" alt="圖十六、只能插入 string 類型的值" width="880" height="117"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;因此我們就可以使用 union 來做積極註記，如此一來錯誤就被解決嚕!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Je1jIsN6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AFs1kDmon2XCkYTLk9vrxuQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Je1jIsN6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AFs1kDmon2XCkYTLk9vrxuQ.png" alt="圖十七、使用 union 做積極註記" width="785" height="105"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;小結：這篇測試了比較多種的情況，經過親手測試後會對於錯誤印象更加深刻不過理所當然的花費的時間比較長一點。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>【TypeScript 30】Day 3：函式型別</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Fri, 25 Nov 2022 04:59:35 +0000</pubDate>
      <link>https://dev.to/angushyx/typescript-30-day-3han-shi-xing-bie-4gp5</link>
      <guid>https://dev.to/angushyx/typescript-30-day-3han-shi-xing-bie-4gp5</guid>
      <description>&lt;p&gt;繼昨天提到的基礎物件型別後，接著就來看看同為物件型別中的函式型別吧 ( JS 中所有東西都是&lt;strong&gt;物件&lt;/strong&gt;或純值 )。&lt;/p&gt;

&lt;h2&gt;
  
  
  物件型別之函式型別 Object Types
&lt;/h2&gt;

&lt;p&gt;這篇一樣要看函式型別的&lt;strong&gt;推論與註記&lt;/strong&gt;是如何運作的，首先從最基本的開始看起，宣告一個 simpleFunction 的函式，型別推論出來的結果是 () =&amp;gt; void也就代表 &lt;strong&gt;輸出端是空的 **或代表&lt;/strong&gt;不回傳的狀態。**&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdsunovm714z20427q6p.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fxdsunovm714z20427q6p.png" width="800" height="85"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;目前的參數是空的，如下圖，如果加入了參數之後呢 ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5edbdgqn1oddsbnl4vj.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fp5edbdgqn1oddsbnl4vj.png" width="800" height="334"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TypeScript 就對參數提出意見了，在這裡要注意下錯誤訊息，TypeScript 在這裡把參數判斷為 any 不過 TypeScript 在意的點是沒有對參數&lt;strong&gt;進行型別的判斷&lt;/strong&gt;，不過 Day 1 我們有提到對於 TypeScript 是不太管 any 這個型別的。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchfxhht9ytcutrqvhyum.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fchfxhht9ytcutrqvhyum.png" width="800" height="150"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;** Implicit Any — 當沒有設置參數型別時，TS 就會很貼心的幫我們把值設置為 any 達到警告的效果。*&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;為何 TS 突然在意起 any 型別了呢 ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;TS 如果要推論出函式輸出的型別的話，前提是要先知道輸入的型別是甚麼。&lt;/p&gt;

&lt;p&gt;假設有個相加的函式 addition 在參數 num1、num2 ，在型別是 any 的情況下，此函式輸出的結果可能會是數字的 "17 " 又或者是字串連接的 "89"，如此一來我們就得猜當時寫這個函式的開發者預期輸出、輸入的型別與結果，對於維運專案的人員來說是很大的精神消耗。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid3bzofzdq1p8vglu60o.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fid3bzofzdq1p8vglu60o.png" width="800" height="450"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如果今天我們把參數的型別故意定義成 any 的話 shouldBeString 會得到數字的 17 ，不過如同此常數的名稱，經過我們的型別註記後，此 output 結果理應要是 string 才對。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85g81t2aaci4dubs72y7.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F85g81t2aaci4dubs72y7.png" alt="錯誤的情況、TS 也不會報錯" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在大部分正常的使用 TypeScript 的情況之下，我們不會特意幫型別定義為 any 尤其是參數的部分，因此，個人認為 TypeScript 很貼心的地方就在這裡了，註記參數的型別時，會給你 *Implicit Any *並警告你必須要註記對應的參數才行。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;輸入型別推論輸出型別&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;講了這麼多來看看 TypeScript 的厲害吧，當我們把參數都註記為 number 時，TS 竟然可以直接幫我們把 return 的結果推論出來了 !!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8r7k0lbc3wmtw1af9cuw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F8r7k0lbc3wmtw1af9cuw.png" width="774" height="198"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;加入空字串後更加確定 TS 神奇的地方了，在這裡並沒有報出錯誤，如同 Day 1 的原始型別 &lt;strong&gt;( **Primitive Types&lt;/strong&gt;)**一樣，自動幫我們把 addition 這個函式推論為字串。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b7gkpr4yoa0l4s33knp.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F0b7gkpr4yoa0l4s33knp.png" width="730" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;想要讓輸出的值都是同一種型別的話該怎麼做呢 ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;直接在參數後面加上欲輸出的型別，在這裡會有兩個地方被 TS 抓毛病。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wf7s1eigyun4u4idkur.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2F6wf7s1eigyun4u4idkur.png" width="800" height="421"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;因為已經定義好 output 的型別了，因此 TS 不允許 return 的地方有其他類別出現。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9c1o2mkdpb4h6ni16xo.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fu9c1o2mkdpb4h6ni16xo.png" width="681" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;一樣的 TS 還是會幫我們推論出型別。&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwb5ywthezbjjyonig1w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://media2.dev.to/dynamic/image/width=800%2Cheight=%2Cfit=scale-down%2Cgravity=auto%2Cformat=auto/https%3A%2F%2Fdev-to-uploads.s3.amazonaws.com%2Fuploads%2Farticles%2Fhwb5ywthezbjjyonig1w.png" width="779" height="122"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;小結：漸漸明白為何專案的系統架構一大使用 TypeScript 帶來的好處，無非就是維運上的方便以及用更多程式語言替代溝通的成本，基本物件型別裡剩下陣列還沒有介紹到，很多觀念也都是環環相扣，也有很多 TS 特有的方法可以使用，敬請期待下一篇的介紹~&lt;/p&gt;

</description>
      <category>softwaredevelopment</category>
    </item>
    <item>
      <title>【TypeScript 30】Day 2：物件型別</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Wed, 23 Nov 2022 02:05:13 +0000</pubDate>
      <link>https://dev.to/angushyx/typescript-30-day-2wu-jian-xing-bie-o58</link>
      <guid>https://dev.to/angushyx/typescript-30-day-2wu-jian-xing-bie-o58</guid>
      <description>&lt;h2&gt;
  
  
  【TypeScript 30】Day 2：物件型別
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--m9JZFIwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2A4R8q9GVSmeg67uIAkH8cng.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--m9JZFIwc--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2400/1%2A4R8q9GVSmeg67uIAkH8cng.png" alt="" width="880" height="440"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;前一篇文章有提到型別的分類，也介紹了最基本的&lt;strong&gt;原始型別 Primitive Types：&lt;/strong&gt;number, string, boolean, undefined, null等等的類型，緊接著就來介紹&lt;strong&gt;物件型別 Object Types。&lt;/strong&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;物件型別 Object Types：*從原始型別或物件型別組合出來的複合型態&lt;/strong&gt;*&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;其中包括了：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;基礎物件型別&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TypeScript 擴充型別&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;函式型別 Function Type&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;這篇會主題是&lt;strong&gt;基礎物件型別&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;首先一開始先測試看看一個簡單的物件，裡面包含了字串、數字以及布林等等不同的型別，像這樣。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--IykV7sT8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AWdDvx2a11Sizqg9W9Pj_oA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--IykV7sT8--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AWdDvx2a11Sizqg9W9Pj_oA.png" alt="" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  型別推論
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;經過上一篇了解的型別推論，讀者可能會有幾種不同的答案，&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;info 被推論為 object&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;info 裡面的屬性被一一推論出型別&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;實際上 TypeScript 非常聰明的幫我們推論出各個屬性的型別。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tGKDvg85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Av84JwZ_faPt19h7vHrHUmg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tGKDvg85--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Av84JwZ_faPt19h7vHrHUmg.png" alt="" width="671" height="254"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;聰明如你又會想說，那 Nullable Type 會被推論為 any 嗎 ?&lt;/p&gt;

&lt;p&gt;竟然是 undefined 和 null!!!&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Vb2aZlIY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AS_8QB5SXkrYjTo8Ywbwhyg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Vb2aZlIY--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AS_8QB5SXkrYjTo8Ywbwhyg.png" alt="" width="728" height="206"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那接下來我們一起來耍耍 TypeScript 吧 !!&lt;/p&gt;

&lt;p&gt;設計幾種不同的情境：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;個別覆寫屬性值&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--gIyWvD4p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2ACsxR28HlsF1Xy2HxjzOTKg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--gIyWvD4p--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2ACsxR28HlsF1Xy2HxjzOTKg.png" alt="" width="880" height="1005"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;看完昨天的文章大家應該都猜得到答案了吧，&lt;/p&gt;

&lt;p&gt;沒錯，覆寫相同的型別可以正常執行，不過一但更改了一開始宣告好的型別後 TypeScript 就無情地拋出錯誤了。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ImgQVXuW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AkmbSO1bYoM6UqE4a-ccCGg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ImgQVXuW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AkmbSO1bYoM6UqE4a-ccCGg.png" alt="" width="830" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;以物件型態覆寫屬性值&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;不同於第一種覆寫方式，這裡直接把建立新 object 並重新定義屬性值&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tvhnHnnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2ATMICVqC5W0pldDZWmSgcqg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tvhnHnnz--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2ATMICVqC5W0pldDZWmSgcqg.png" alt="" width="880" height="1133"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TypeScript 厲害的地方來了，不僅幫我們監督型別了，甚至屬性都要完全符合一開始宣告的內容才可以&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--9CX4p2tF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AY54Ew820b_9hpXuCvXRmtA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--9CX4p2tF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AY54Ew820b_9hpXuCvXRmtA.png" alt="" width="833" height="465"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;對於一開始直接 JS 這種弱型別語言的我更加了解強型別程式語言的嚴謹，以及事先規劃資料屬性的重要性，的確這樣一來就可以完完全全掌握住該物件的屬性以及方法，方法的部分後面會再提到。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--iE9PTgrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AOMBPu67mbSC9H22Uor3ZjA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--iE9PTgrE--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AOMBPu67mbSC9H22Uor3ZjA.png" alt="多一個/少一個屬性各別的錯誤訊息" width="805" height="609"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;新增物件屬性值&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;這就有點像第一個情境加上第二個情境的多一個屬性值了，同樣的 TypeScript 不允許半路殺出一個屬性值出來。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--pE7awEN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Abxk8ff7E9LffmktsTNwwpQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--pE7awEN7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Abxk8ff7E9LffmktsTNwwpQ.png" alt="" width="684" height="166"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;基本的物件型別測試完後，來點複雜的物件包物件的情況。&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--N9BMrz-c--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AGtyBct-llx1fmNEnojUghw.png" alt="" width="673" height="755"&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  型別註記
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;看完了object 的型別註記後，那有 object 的型別註記嗎 ?&lt;/p&gt;

&lt;p&gt;當然有的， 我們拿上面的 blogs 的資料形式來當做例子：&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--ke5VHof7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2AHiKqk7jp4J4CY0DlFDEgnQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--ke5VHof7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2104/1%2AHiKqk7jp4J4CY0DlFDEgnQ.png" alt="" width="880" height="1196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;比較令人意外的是，情境 1. 和 3.，這樣看起來和 Immutable 有著異曲同工之妙，如果有使用過 React 或 Redux 開發的讀者應該對 Immutable 不陌生( Vue or Angular 不太熟悉 ) ，&lt;strong&gt;簡單來說就是不能細部微調物件，而是直接修改整個物件。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hLreaO8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ANAOiEtTzOfG6MHWVa9iHgA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hLreaO8H--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ANAOiEtTzOfG6MHWVa9iHgA.png" alt="" width="748" height="654"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;小結：typeScript 中對於物件的型別推論與註記其實和原始型別一樣，不過有幾個點要特別注意，分別是 ( 1 ) 當使用推論時必須完全按照一開始定義好的物件型別與格式 ( 2 ) 當進行物件的型別註記時不能細微調整，而是把整個物件重新定義格式 ( Immutable ) 要改就改全部。&lt;/p&gt;

</description>
    </item>
    <item>
      <title>【TypeScript 30】Day 1：型別推論及註記</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Sun, 06 Nov 2022 12:41:32 +0000</pubDate>
      <link>https://dev.to/angushyx/typescript-30-day-1xing-bie-tui-lun-ji-zhu-ji-o2n</link>
      <guid>https://dev.to/angushyx/typescript-30-day-1xing-bie-tui-lun-ji-zhu-ji-o2n</guid>
      <description>&lt;h2&gt;
  
  
  【TypeScript 30】Day 1：型別推論及註記
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--tCsDvcMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aw3pX-UxawOa8Xdktu3mGPg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--tCsDvcMm--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Aw3pX-UxawOa8Xdktu3mGPg.png" alt="" width="192" height="192"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;距離上次寫文章已經相隔了四個月，在這四個月期間大量練習了 React、node.js、Boostrap 等等技術，也大致上掌握以上技術的核心，也因此都沒有好好沉澱寫文章，最近在學習 Next.js、typeScript 以及 tailwindcss，因為對於 React、Boostrap 都蠻熟習的，因此在學習 Next.js 和 tailwind 上 gap 比較小，相對的 typeScript 就比較需要花時間研究，接下來就聊聊 typeScript 吧!!!&lt;/p&gt;

&lt;p&gt;最一開始來建置 ts 專案，因為平常習慣使用 React 開發，就使用方便的 create react app 吧。&lt;/p&gt;

&lt;h3&gt;
  
  
  Insatll
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npx create-react-app ts-30 --template typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;或&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn create react-app ts-30 --template typescript
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;安裝完後，緊接著安裝使用 typeScript 時所需要的套件，一樣可以選擇使用 npm 或是 yarn&lt;/p&gt;

&lt;h3&gt;
  
  
  Install
&lt;/h3&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;npm install — save typescript @types/node @types/react @types/react-dom @types/jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;或&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add typescript @types/node @types/react @types/react-dom @types/jest
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;接著在專案中安裝 eslint 以及 prettier 模組&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;yarn add prettier eslint-config-prettier eslint-plugin-prettier eslint-plugin-react-hooks
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;再加入設定檔於 /src 底下，專案建立完成後，先來釐清最基本的觀念【型別推論及註記】&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--yAtX0rK3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3798/1%2Ad8hhe2ZeVR87pGtfkFpCtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--yAtX0rK3--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/3798/1%2Ad8hhe2ZeVR87pGtfkFpCtQ.png" alt="" width="880" height="483"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;h1&gt;
  
  
  &lt;strong&gt;【型別推論&lt;/strong&gt;（Inference）&lt;strong&gt;及註記&lt;/strong&gt;（Annotation）&lt;strong&gt;】&lt;/strong&gt;
&lt;/h1&gt;
&lt;/blockquote&gt;

&lt;p&gt;下面就要來介紹個別的原理以及使用時機&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;型別大致上分為幾種&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;原始型別 Primitive Types ：&lt;/strong&gt;number, string, boolean, undefined, null ES6 的 symbol與時常會在&lt;strong&gt;函式型別&lt;/strong&gt;裡看到的 void皆屬於&lt;strong&gt;原始型別。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;物件型別 Object Types：&lt;/strong&gt;這些型別的共同特徵是 — — &lt;strong&gt;&lt;em&gt;從原始型別或物件型別組合出來的複合型態&lt;/em&gt;&lt;/strong&gt;（比如物件裡面的 Key-Value 個別是 string 和 number 型別組合成)&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;基礎物件型別：JSON 物件，陣列，類別以及類別產出的物件（也就是 Class 以及藉由 Class &lt;em&gt;new&lt;/em&gt; 出來的 Instance）&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;TypeScript 擴充型別：Enum、Tuple(皆內建於 TS )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;函式型別 Function Type：型別樣貌像是 ( input ) =&amp;gt; ( output )&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;&lt;strong&gt;明文型別 Literal Type：&lt;/strong&gt;值的本身也可以成為一個型別。如下圖，常數 string 被賦值 ' hello ts ' ，直接被宣告為 string 類型。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6M2AMJM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2120/1%2A0sR2Ho8B3k1DKxF-2O5nHg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6M2AMJM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2120/1%2A0sR2Ho8B3k1DKxF-2O5nHg.png" alt="" width="880" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;特殊型別&lt;/strong&gt;：參考的部落格作者所細分出的型別，即 any、never即以及 unknow ，這三種看起來都是沒有被定義型別所衍生出的型別，後面會介紹他們的差異。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;複合型別&lt;/strong&gt;：同上，即 union 與 intersection 的型別組合，但是跟其他的型別的差別在於：這類型的型別都是由邏輯運算子組成，分別為 | 與 &amp;amp;。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;大致上將 typeScript 的型別多分類後，我們先回到最一開始要介紹的主題：型別推論及註記的原理以及使用時機&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;&lt;strong&gt;型別推論：&lt;/strong&gt;還記得上面的這張圖嗎 ? 完美的展示了型別推論，typeScript 會&lt;strong&gt;自動幫你推論型別。&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--6M2AMJM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2120/1%2A0sR2Ho8B3k1DKxF-2O5nHg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--6M2AMJM0--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2120/1%2A0sR2Ho8B3k1DKxF-2O5nHg.png" alt="" width="880" height="159"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不過讀者也許會思考那這樣 ts 和 js 的寫法哪裡不一樣了呢 ? 在這個案例中 typeScript 的確是幫我們把型別定義好，不過在更多情況下 ts 會把型別定義為 any那既然都已經使用 typeScript 開發了，當然還是不要讓型別是 any 的情況發生。&lt;/p&gt;

&lt;p&gt;如下圖，如果把 nothing 這個變數設置為undefiend數就會被定義為 any ，正常情況下這邊並不會爆出錯誤，不過因為已經使用了 eslint ，所以這個錯誤直接被 eslint 判斷出來。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--oJ5ptAKs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2416/1%2AetkejYB0wWeoa7T3z6vuAw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--oJ5ptAKs--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2416/1%2AetkejYB0wWeoa7T3z6vuAw.png" alt="" width="880" height="277"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;
&lt;em&gt;此類 null 跟 undefined 稱為 **Nullable Types *&lt;/em&gt;這類 *&lt;em&gt;Nullable Types *&lt;/em&gt;會被推論為 any。*&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;不過，型別推論的本意並不是在這裡，而是當變數已經被推論過後，ts 就會跳出警告 — 不能再更改其型別。&lt;/p&gt;

&lt;p&gt;拿上面 string這個變數例子，如果重新賦值該變數為數字型別的 22 ts 的型別小蚯蚓就跑出來了。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--cpvFrlv---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2580/1%2A9ahlvRtPgAotKvuDPiVJ3w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--cpvFrlv---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2580/1%2A9ahlvRtPgAotKvuDPiVJ3w.png" alt="" width="880" height="86"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TypeScript 就會提出這個變數應該是 string 類型這個質疑。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3L1059ZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2934/1%2A8eXqF43l_pkX7oBpK9Dw4A.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3L1059ZM--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2934/1%2A8eXqF43l_pkX7oBpK9Dw4A.png" alt="" width="880" height="74"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那在這邊我們回到剛剛所提到的 &lt;em&gt;**Nullable Types *&lt;/em&gt;*測試看看，並不會跳出紅色蚯蚓。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--xeFNonij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AwF8wk-skyi_LvOzmFYyyRg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--xeFNonij--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AwF8wk-skyi_LvOzmFYyyRg.png" alt="" width="880" height="501"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;檢查完型別後會發現是 any，結論就是當型別被定義為 any 時某種程度上就已經失去使用 TypeScript 幫我們監督程式碼的本意了，因此在大多情況之下，盡量避免讓型別是 any 。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--elNcSf3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AURjYXel1jX6-Y1nxOVR_Hw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--elNcSf3---/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AURjYXel1jX6-Y1nxOVR_Hw.png" alt="" width="775" height="95"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h3&gt;
  
  
  遲滯性初始 Delayed Initialization
&lt;/h3&gt;

&lt;p&gt;除了沒有定義好型別之外，還有一種狀況會出現 any，就和原生的 JS 類似，當今天先定義了變數後，不直接指派值，&lt;strong&gt;而是程式碼執行到後面才賦值&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Dj4Ln1np--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AdKewmiacsBuRR5Dr4Vf_MA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Dj4Ln1np--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AdKewmiacsBuRR5Dr4Vf_MA.png" alt="" width="880" height="381"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;在這邊 TS 已經把 testVariables 這個變數的型別認定為 any ，因此後面無論賦值是字串或是數字，TypeScript 都並不會檢查出錯誤。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--swCrzlFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_8Pc-CeByEbJPNiCdn2NCA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--swCrzlFF--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_8Pc-CeByEbJPNiCdn2NCA.png" alt="" width="782" height="136"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;概念其實就與我們剛剛提到的 &lt;em&gt;**Nullable Types *&lt;/em&gt;&lt;em&gt;有關，當只有宣告變數而沒有給他值時，該值自然就是 *&lt;/em&gt;&lt;em&gt;Nullable Types *&lt;/em&gt;*的 undefined，也因此型別就等於是 any 。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--Xr0VRXsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A035h5HT-WGh3GgBjnN8-Pg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--Xr0VRXsW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A035h5HT-WGh3GgBjnN8-Pg.png" alt="" width="806" height="155"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;如何避免 any 的型態出現 — — 型別註記 ( Type Annotation )&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;我們將 absoluteNothingVariables 和 absoluteNullVariables註記型別後再重新賦值&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--qAF1clGS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2Aiwh2Y__g36dBvbq37FbR9Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--qAF1clGS--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2Aiwh2Y__g36dBvbq37FbR9Q.png" alt="" width="880" height="411"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;TypeScript 就會把錯誤拋出來了&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--R6LCuRq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ay6V9vIURx51I7Ljz7aL6Vw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--R6LCuRq_--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2Ay6V9vIURx51I7Ljz7aL6Vw.png" alt="" width="798" height="177"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;再測試看看&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K6voxCOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AintKOxR1OLRLnxxSCnLhGA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K6voxCOw--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2220/1%2AintKOxR1OLRLnxxSCnLhGA.png" alt="" width="880" height="471"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;可以發現，經過型別註記後重新賦與註記的型別 ( 這裡是 string ) 後，接下來重新賦予 string 類型的值並不會出錯，不過一但清除為 undefined 或 null 就跳出錯誤，原因是： TS 已經將 stringVariable認定為 string 類型。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--rWJUV-Sf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AAW9xR3cqdX225MuzrO7FRQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--rWJUV-Sf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AAW9xR3cqdX225MuzrO7FRQ.png" alt="" width="782" height="265"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;不過如果還沒指派值之前就使用該變數，那這個 stringVariable雖然已經進行型別註記了，不過該值也還是 undefiend 不是嗎 ?&lt;/p&gt;

&lt;p&gt;來嘗試看看，就像這樣，在annotationString 還沒賦值的情況之下，先使用了該變數&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--QEvQbfrh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxPKcrt55xw4J1RayGfdofg.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--QEvQbfrh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxPKcrt55xw4J1RayGfdofg.png" alt="" width="880" height="527"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;跳出的錯誤非常明顯指出不能在還沒賦值時就使用該變數，有寫過 JS 的讀者應該對於這個問題比較熟悉，概念有點像 TDZ （Temporal Dead Zone，暫時性死區）這個討論範圍就延伸到了 JavaScript 的作用域，因此就不在這裡多做討論了。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--FFqTka1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A4tIiccFUClap4Vb7Isq0ZQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--FFqTka1O--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A4tIiccFUClap4Vb7Isq0ZQ.png" alt="" width="857" height="202"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;小結：起初想說 TypeScript 不就只是加入型別而已沒甚麼，聽到大家說TypeScript 學習門檻很高，不太相信，不過經過這兩到三天的整理發現好像其實並不只是單純的加入型別這樣而已，剛開始就冷汗直流，希望能夠讓整理文章的速度再快一點。&lt;/p&gt;

&lt;p&gt;參考資料：&lt;br&gt;
&lt;a href="https://ithelp.ithome.com.tw/articles/10214719"&gt;&lt;strong&gt;Day 02. 前線維護・型別推論 X 註記 - Type Inference &amp;amp; Annotation - iT 邦幫忙::一起幫忙解決難題，拯救 IT 人的一天&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://create-react-app.dev/docs/adding-typescript/"&gt;&lt;strong&gt;Adding TypeScript | Create React App&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://hiskio.com/account/courses?tab=completed&amp;amp;type=course"&gt;&lt;strong&gt;HiSKIO 專業技能線上學習平台 | 來自全球高品質的職場專業課程&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
      <category>webdev</category>
      <category>typescript</category>
    </item>
    <item>
      <title>使用 Next.js + typeScript + tailwind 建置個人網站</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Wed, 02 Nov 2022 05:40:03 +0000</pubDate>
      <link>https://dev.to/angushyx/shi-yong-nextjs-typescript-tailwind-jian-zhi-ge-ren-wang-zhan-1cpa</link>
      <guid>https://dev.to/angushyx/shi-yong-nextjs-typescript-tailwind-jian-zhi-ge-ren-wang-zhan-1cpa</guid>
      <description></description>
    </item>
    <item>
      <title>Session 與 Cookie</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Wed, 02 Nov 2022 02:39:33 +0000</pubDate>
      <link>https://dev.to/angushyx/session-yu-cookie-30hb</link>
      <guid>https://dev.to/angushyx/session-yu-cookie-30hb</guid>
      <description>&lt;h2&gt;
  
  
  【筆記】Session 與 Cookie
&lt;/h2&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--OaBVWzL6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AA-5hXPGarbWJCPae" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--OaBVWzL6--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AA-5hXPGarbWJCPae" alt="Photo by [Chaman Raj ](https://unsplash.com/@chamanraj)form [unsplash](https://unsplash.com/)" width="880" height="1100"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;為什麼我們會需要 Session 和Cookie ?&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;在這邊要先提到 HTTP 無狀態(stateless)的特性，這個特性會讓每個 HTTP 請求都是獨立的，也因為這個原因使得瀏覽器無法紀錄網路上的行為，所以當今天使用者重開頁面，想要登入同一個網站時，就必須要不斷重複的輸入帳號以及密碼，因此就需要透過 Cookie 和 Session 來記錄狀態。&lt;/p&gt;

&lt;h3&gt;
  
  
  &lt;strong&gt;保存使用者狀態方法&lt;/strong&gt;
&lt;/h3&gt;

&lt;p&gt;*&lt;em&gt;Cookie *&lt;/em&gt;：描述&lt;em&gt;『client 與 server 目前溝通狀態』 的資料&lt;/em&gt;&lt;/p&gt;

&lt;p&gt;client 與 server 間的溝通需透過 HTTP，但就如同我們上面提到的 HTTP是無狀態的，各個 request 都是獨立的個體，所以 Server 端無法記住 Client 目前的狀態。&lt;/p&gt;

&lt;p&gt;Cookie是瀏覽器提供的一個儲存空間，提供了保存狀態資訊的功能，為了讓 server 端可以在 client 瀏覽器上記住、儲存 client 的狀態而生。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cookie 由瀏覽器處理，具有兩個特性：&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;只在特定網域上起作用，簡單來就是在 A 網域存入的 cookie 是不會出現在 B 網域的。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;有生命期限：到了生命期限後 cookie 將會失效，可自定義。&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cookie 的資料屬性&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p&gt;domain 和 path: 設定關於 Cookie 的網域以及路徑。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;expires / max-age: 設定 Cookie 資料過期的時間， expires 必須是一個日期，max-age 則是秒數。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;size: cookie 資料的大小，單位是 bytes。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;HttpOnly: 設定 cookies 的資料只能透過 server 讀取，也就是說 js 程式碼無法讀取，設定 HttpOnly 可以避免 XSS 攻擊，例如駭客可以透過嵌入&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Cookie&lt;/strong&gt; 的缺點&lt;/p&gt;
&lt;/blockquote&gt;
&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Cookie 上所有的數據在client 端是可以被修改的，使數據容易被偽造&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;字段太多會影響傳輸效率&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Cookies size 限制: 一個 Cookies 最大可以是 4096 bytes，而一個 domain 最多只能有 20 cookies。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;所以在實際中，Cookies大多用來存放結構簡單、容量小且無意義的資訊，而像是帳號密碼這種比較敏感的資訊就不太適合放在Cookie 上。&lt;/p&gt;

&lt;h2&gt;
  
  
  &lt;em&gt;Session：更安全的狀態管理機制&lt;/em&gt;
&lt;/h2&gt;

&lt;p&gt;為了補足 Cookie 的缺點，我們會在 Server 端使用 Session 的機制去儲存這些&lt;strong&gt;狀態資訊&lt;/strong&gt;，並產生一組 Session key 放入 Cookie 中，因為這些狀態資訊都是存在於 &lt;strong&gt;Server 端&lt;/strong&gt;，因此使用者無法讀取， 使用者只能看到 session key 但不知道結構，同時也能避免 Cookie 存入過多資料，解決了Cookie ****的缺點。&lt;/p&gt;

&lt;p&gt;打個比方，在現實生活中Cookie像是餐券，Session則是會員卡，Session可以靠著Session ID 記錄你點餐的細節、甚至是消費紀錄和喜好，可以解決而 Cookie 遺失的問題。&lt;/p&gt;

&lt;p&gt;總結：&lt;/p&gt;

&lt;p&gt;session：將數據保留在 Server 端並且產生出 Session ID，而 Session ID 就是憑證，是Server端所發的識別證&lt;/p&gt;

&lt;p&gt;cookie：是瀏覽器&lt;strong&gt;存放資料的地方&lt;/strong&gt;，可以存放seesion之類的資料&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--JU5QRBgf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ASmZz214p2MXpYNB-K9vSwQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--JU5QRBgf--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ASmZz214p2MXpYNB-K9vSwQ.png" alt="" width="657" height="779"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;參考連結：&lt;br&gt;
&lt;a href="https://vicxu.medium.com/authentication-%E9%82%A3%E4%BA%9B%E5%B0%8F%E4%BA%8B%E4%B8%8A%E9%9B%86-cookie-%E8%88%87-session-%E4%BB%8B%E7%B4%B9-1da2d413afa2"&gt;&lt;strong&gt;Authentication 那些小事上集：Cookie 與 Session 介紹&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/tsungs-blog/day14-session%E8%88%87cookie%E5%B7%AE%E5%88%A5-eb7b4035a382"&gt;&lt;strong&gt;Day14-Session與Cookie差別&lt;/strong&gt;&lt;/a&gt;&lt;br&gt;
&lt;a href="https://medium.com/johnny%E7%9A%84%E8%BD%89%E8%81%B7%E5%B7%A5%E7%A8%8B%E5%B8%AB%E7%AD%86%E8%A8%98/node-js-cookie-session%E9%A9%97%E8%AD%89%E5%8E%9F%E7%90%86%E4%BB%A5%E5%8F%8Aexpress-session%E5%A5%97%E4%BB%B6%E4%BD%BF%E7%94%A8-aeafa386837e"&gt;&lt;strong&gt;[Node.js] cookie-session驗證原理以及express-session套件使用&lt;/strong&gt;&lt;/a&gt;&lt;/p&gt;

</description>
    </item>
    <item>
      <title>【JS必學】 同步以及非同步 — Callback + Promise + Async/Await</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Wed, 02 Nov 2022 02:11:35 +0000</pubDate>
      <link>https://dev.to/angushyx/jsbi-xue-tong-bu-yi-ji-fei-tong-bu-callback-promise-asyncawait-4dkm</link>
      <guid>https://dev.to/angushyx/jsbi-xue-tong-bu-yi-ji-fei-tong-bu-callback-promise-asyncawait-4dkm</guid>
      <description>&lt;h2&gt;
  
  
  【JS必學】 同步以及非同步 — Callback + Promise + Async/Await
&lt;/h2&gt;

&lt;p&gt;最近實做了一個縮網址產生器的小作業，更大量的使用 node.js ，因此要來好好面對逃避很久的 Callback + Promise + Async/Await 這個主題，也是為了更深入了解 JavaScript 。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--C3tj4ZUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AaNthbfhF5ltvIha9" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--C3tj4ZUu--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2AaNthbfhF5ltvIha9" alt="" width="880" height="598"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  同步與非同步
&lt;/h2&gt;

&lt;p&gt;在說明 Callback + Promise + Async/Await之前先來談談一個概念：同步與非同步。&lt;/p&gt;

&lt;p&gt;同步：等待第一個任務完成後才接續下個任務，程式碼一行一行執行。&lt;/p&gt;

&lt;p&gt;非同步：和同步執行相反，程式碼不用逐行照著順續執行。&lt;/p&gt;

&lt;p&gt;舉個例子：假設目前有行程式碼是需要等待2秒鐘來下載圖片，後面還有其他動作要處理，如果是使用同步執行，就必須等待圖片下載完成後，後面的程式碼才會接續執行，因此等待的這兩秒就會延遲到後面程式碼的運行。&lt;/p&gt;

&lt;p&gt;不過如果今天是非同步執行，可以達到下載照片，同時執行後面兩行程式碼的效果。換個例子 JavaScript 向第三方伺服器發出請求，就會牽涉到網路，而網路的速度和穩定性是不可預期的可能會阻塞，所以需要透過非同步的方式來同時處理多組事件的效果，簡單來說非同步執行可以防止執行程序的阻塞。&lt;/p&gt;

&lt;p&gt;來看看以下的範例：&lt;/p&gt;

&lt;p&gt;同步執行比較好理解，下面的例子中 JavaScript 先執行了 console.log(‘hello’) 後再執行 console.log(‘world’)，所以最後在開法者工具會得到先被執行的 hello 和 world。&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(“hello”);

console.log(“world”);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--5298RhNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A5XMpa8z47r6RgiXQW1FFfw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--5298RhNe--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A5XMpa8z47r6RgiXQW1FFfw.png" alt="" width="832" height="72"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;再來是不讓耗時任務阻塞的非同步執行：&lt;/p&gt;

&lt;p&gt;來說明一下發生了什麼事，hello 和 hola 同時印在開發者工具上，而 world 則等待了 3 秒後才被印出來，程式碼其實是一行接著一行執行的，所以其實在印出 hola 前已經先執行了 setTimeout不過因為是非同步執行， JavaScript 並不會等待三秒後才印出下面的 hola 。&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;console.log(“hello”);

setTimeout(() =&amp;gt; console.log(“world”), 3000);

console.log(“hola”);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--PZYKPsKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AdEjCsLFWcUn5aiFLTgFG6w.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--PZYKPsKh--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AdEjCsLFWcUn5aiFLTgFG6w.png" alt="" width="880" height="92"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;h2&gt;
  
  
  Callback (回調)
&lt;/h2&gt;

&lt;p&gt;首先，先來談談 callback ，什麼是 callback ? 我們都知道，JavaScript 中的函數是一級函數，說成白話一點就是他的函數能夠像物件一樣當成參數傳入另一個函數裡，而作為參數傳入另一個函數的函數執行後，他就是一個 callback function ，那聰明的大家應該就會想到，如果參數裡面不斷的使用函數，這個最外層的函數的功能不就可以變得很強大嗎 ?&lt;/p&gt;

&lt;p&gt;上面有先簡單介紹過了非同步執行，而 callback function 就是處理非同步執行的方式之一。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;常見的例子&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;除了一開始介紹的 setTimeout 是常見的例子之外，還有：&lt;/p&gt;

&lt;ul&gt;
&lt;li&gt;DOM 事件監聽&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;這裡的callbackFunctionName 是一個函數參數，也就一個callbackFunction，在點擊事件還沒發生之前，這個函數都不會改變，而當未來點擊事件發生時，才會執行這個 callbackFunction，所以簡單來說，就是需要執行 addEventListener 這個函數 callbackFunctionName 才會被執行，這就是回呼函式(callback function)&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;const btn = document.querySelector(“btn”);

btn.addEventListener(“click”, callbackFunctionName);
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;目前我們看到了JavaScript 一級函數 — 所有東西都是物件，以及將函數當成物件的 callback function 的強大，那我們現在來看看他的缺點：&lt;/p&gt;

&lt;p&gt;在這個例子中可以看到回呼函數裡包著另一個回呼函數，目前只有兩個函數，如果回呼函數有 5個、10個呢 ?&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;login('username', 'password', (res) =&amp;gt; {
    if (res.result === 0) {
        getPosts(res.uid, (posts) =&amp;gt; {
            if (posts &amp;amp;&amp;amp; posts.length) {
                console.log('你的文章有 ' + posts.length + ' 篇');
            } else {
                console.log('沒有文章');
            }
        });
    } else {
        console.log('登入失敗');
    }
});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;就變成經典的 callback hell了&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--K9wl_GqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2Av4xM-C8UhhmVy2kq.jpg" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--K9wl_GqQ--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/0%2Av4xM-C8UhhmVy2kq.jpg" alt="Photo by [Day 14 — 二周目 — 從Promise 昇華到 async/await](https://ithelp.ithome.com.tw/articles/10201420)" width="721" height="420"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;我們可以很明顯得看出 callback hell 的劣勢，一層層嵌套的程式碼不利於閱讀與修改，隨著 JavaScript 的不斷迭代，產生了 Promise 以及 asyns await，首先先來介紹 Promise。&lt;/p&gt;

&lt;h2&gt;
  
  
  Promise
&lt;/h2&gt;

&lt;p&gt;這是 callback function 編寫出的程式碼&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--s2xm8hHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYTJWD8g7BpLrkk5dQkrWgw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--s2xm8hHG--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AYTJWD8g7BpLrkk5dQkrWgw.png" alt="" width="880" height="219"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;使用 Promise 寫出的程式碼，我想大部分的人應該都會覺得 Promise 看起來比較直觀，也比較容易維護吧 ?&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--SyEcOJdW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ATUrQp2a6Qo4ipAx4DywCtQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--SyEcOJdW--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2ATUrQp2a6Qo4ipAx4DywCtQ.png" alt="" width="880" height="160"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;Promise 的出現是為了讓我們能夠更簡潔的寫出 callback&lt;/p&gt;

&lt;blockquote&gt;
&lt;p&gt;&lt;strong&gt;Promise — 承諾&lt;/strong&gt;&lt;/p&gt;
&lt;/blockquote&gt;

&lt;p&gt;看完例子後來說明一下 Promise 的本質，如同字面上翻譯，Promise 就是承諾，承諾什麼呢 ?&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;Promise的特點&lt;/strong&gt;&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Promise 的狀態不受外部影響：Promise 代表一個非同步操作有三種狀態&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;pending：初始狀態，不是 fulfilled 與 rejected。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;fulfilled：表示操作成功地完成。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;rejected：表示操作失敗了。&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;只有非&lt;strong&gt;同步操作的結果&lt;/strong&gt;可以決定目前處於何種狀態，任何其他操作都無法改變這個狀態。&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;一但改變狀態，就不會再改變：Promise 的狀態改變只有兩種可能&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;從 pending 到 fulfilled&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;從 pending 到 rejected&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;p&gt;只要其中一種狀態發生了，狀態就不會再改變了，會一直保持這個結果，這時就稱為 resolved（已定型）。&lt;/p&gt;

&lt;p&gt;接著我們來建立 Promise 實例並實作&lt;/p&gt;

&lt;p&gt;一個 Promise 物件是透過 new 關鍵字和它的物件建構子（Constructor）所產生出來的，如同我們上面所說的，這個建構子函式接收一個帶有 resolve 和 reject 兩個參數的函式（executor）&lt;/p&gt;

&lt;p&gt;這裡宣告一個新的 Promise 實體(建構子函式)並接受一個函式，這個函式的參數有兩個，分別是resolve 和 reject 。&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let promise = new Promise((resolve, reject) =&amp;gt; {});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;這邊設置一個情境是 uber 司機接受了小明要去機場的訂單，這是一種承諾，司機承諾小明再他去機場，所已有兩種情境，司機順利載小明到機場resolve 和中途發生意外無法履行承諾reject 。&lt;/p&gt;

&lt;p&gt;用上述的情境我們看到下面的程式碼，當 sentToAirport 的值是 ture時，代表成功送小明到機場也就是旅行了承諾，因此回傳resolve&lt;/p&gt;

&lt;div class="highlight js-code-highlight"&gt;
&lt;pre class="highlight plaintext"&gt;&lt;code&gt;let sentToAirport = true;

let promise = new Promise((resolve, reject) =&amp;gt; {

if (sentToAirport) {

resolve();

} else {

reject();

}

});
&lt;/code&gt;&lt;/pre&gt;

&lt;/div&gt;

&lt;p&gt;那當小明成功被送到機場後，小明還要劃位，而轉換成程式碼就是做下一步動作的意思，因此可以使用.then() 來執行接續的動作。&lt;/p&gt;

&lt;p&gt;這個步驟中 Promise 已經是一個 Promise Object，這個 Object 提供了一個方法( method )，then，意思是當 1 執行完成後，執行 2，2裡須要傳入一個 callback function。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--UPNUnmq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AqgVzMog8kBWEzAO8L1Vm-Q.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--UPNUnmq7--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AqgVzMog8kBWEzAO8L1Vm-Q.png" alt="" width="880" height="319"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;那如果是 rejcet 會回傳什麼呢 ?&lt;/p&gt;

&lt;p&gt;這邊我們把 let sentToAirport = true; 改成 false 讓 if else 判斷執行 reject()，此時就會跳出這條錯誤&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--3C6S8KTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AoBsRzsCbYPGrQI1WLukLDw.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--3C6S8KTL--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AoBsRzsCbYPGrQI1WLukLDw.png" alt="" width="880" height="31"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如果不想要讓開發者工具跳出這段 ‘UnCaught ’就需要在，then 後面加上catch ，&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--fIoXvm0y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxLacLpABJEDnHj4gEUowaA.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--fIoXvm0y--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2AxLacLpABJEDnHj4gEUowaA.png" alt="" width="880" height="324"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;如此一來就可以回調我們自己定義的函數而不是‘UnCaught’ 。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--MFHRcNZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_HvBi86hFprRZkwpz6e06g.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--MFHRcNZV--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2000/1%2A_HvBi86hFprRZkwpz6e06g.png" alt="" width="880" height="30"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;最後來一點 Promise 的總結：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Promise 有效的解決了 callback hell&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Promise 提供 resolve() 和 rejcet() 這兩個函數告知 ‘長任務 ’ 執行的進度&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;then 會在 ‘長任務’ 完成後執行，正常來說 then 裡會寫處理 ‘長任務’ 返回的數據的邏輯&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;當 Promise 被rejcet()就需要使用 catch 來捕捉錯誤，避免產生 ‘UnCaught ’ 的狀況。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;後記：&lt;/p&gt;

&lt;p&gt;已經很久沒有寫部落格了，這次的主題一直很想寫不過一直不斷的拖延，原本要把 Async/Await 也寫進來不過今天的我真的是筋疲力盡了，不過這會讓我明天有個目標，明天一定要寫 Async/Await!!!!!&lt;/p&gt;

</description>
    </item>
    <item>
      <title>【資料結構與演算法】- Big O Notation</title>
      <dc:creator>Angus</dc:creator>
      <pubDate>Tue, 01 Nov 2022 06:37:35 +0000</pubDate>
      <link>https://dev.to/angushyx/zi-liao-jie-gou-yu-yan-suan-fa-big-o-notation-4mip</link>
      <guid>https://dev.to/angushyx/zi-liao-jie-gou-yu-yan-suan-fa-big-o-notation-4mip</guid>
      <description>&lt;h2&gt;
  
  
  【資料結構與演算法】- Big O Notation
&lt;/h2&gt;

&lt;p&gt;Big O Notation 是一種工具：假設有個函式 f(n) 當 input 值放大時 n 的上升曲線大小就是由 Big O Notation 評斷。&lt;/p&gt;

&lt;p&gt;&lt;strong&gt;考慮最糟糕的情況，當 input size 龐大時複雜度的成長趨勢&lt;/strong&gt;&lt;/p&gt;

&lt;p&gt;Big O 算法規則：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;常數不重要( Constants doesn’t matter )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;取最大值 ( Small Terms don’t matter )&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;log底數不重要 ( Logarithm Base doesn’t matter )&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;常見的 Big O 演算法( 好到差 )：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;O(1)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O(logn)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O(n)：最常見的&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O(nlogn)：使用 sorting&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O(n²)：想辦法變成 3 or 4。&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;O(n³)：想辦法變成 3 or 4。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;最理想的狀態是使用 O(1) 和 O(logn)，O(n) 是比較常見的 case，大多 sorting 演算法 Big O 的值都是 O(nlogn)，如果有 O(n²)、或O(n³)要想辦法變成 O(n) 或 O(nlogn) 。&lt;/p&gt;

&lt;p&gt;Q：假設目前有四個 f(n)，這裡可能就會有個疑問是， 1500 也會影響到演算法的速度，為何 f3(n) 的 Big O 值可以直接去掉 1500 呢 ?&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;f1(n) = 1000 — — — — → O(1)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;f2(n) = n — — — — —→ O(n)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;f3(n) = n + 1500 — —→ O(n)&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;f4(n) = n² — — — — — → O(n²)&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;看下表就可以知道，當在 input 值 = 1 時 f1(n) 和 f3(n) 這兩個演算法花費時間明顯大於其他兩種。不過當 input 值提升到 100 時， f4(n) 花費的時間遠遠大於其他幾種演算法，這也是為什麼要盡量避免使用 f4(n) 這種演算法的理由。最後，當 input 值提升到了100000 時，會發現其實 f2(n) 和 f3(n) 花費的時間的差距是最相近的，而文章開頭有介紹到，&lt;strong&gt;Big O Notation 考慮的是最糟糕的情況( worst case scenario )&lt;/strong&gt;，在這個例子中就是 input 值 = 100000，這也是為什麼 Big O Notation 會忽略 1500 的原因。&lt;/p&gt;

&lt;p&gt;&lt;a href="https://res.cloudinary.com/practicaldev/image/fetch/s--hW15XtIl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2688/1%2A9hyboaPBi_6f0Sx147t2pQ.png" class="article-body-image-wrapper"&gt;&lt;img src="https://res.cloudinary.com/practicaldev/image/fetch/s--hW15XtIl--/c_limit%2Cf_auto%2Cfl_progressive%2Cq_auto%2Cw_880/https://cdn-images-1.medium.com/max/2688/1%2A9hyboaPBi_6f0Sx147t2pQ.png" alt="圖源：[資料結構與演算法 (JavaScript)](https://www.udemy.com/course/algorithm-data-structure/)" width="880" height="196"&gt;&lt;/a&gt;&lt;/p&gt;

&lt;p&gt;了解了 Big O Notation 的定義和概念後，接著就來看看原生的 JavaScript 中Array 和 Objcet 的各種方法分別屬於哪種 Big O Notation 吧 !!&lt;/p&gt;

&lt;p&gt;這些方法的功能不外乎就是四種&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;新增 Insertion&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;移除 Removal&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;搜尋 Seaching&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;&lt;strong&gt;取值 Access&lt;/strong&gt;&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;先來看看 Object 做以上四種動作時個別的 Big O Notation：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Insertion → O(1)：不管 Obj 多大，新增屬性時所耗費的時間都是一樣的&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Removal ****→ O(1)：同上，刪除屬性時所耗費的時間一樣&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Seaching → O(n)：從第一個屬性開始找，直到找到為止，花費時間與 Obj 大小成正比&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accessing → O(1)：使用 Hash Tables 這種演算法，因此可以達到不管物件大小取值所耗費的時間都相同的效果 。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;再來是 Array ：&lt;/p&gt;

&lt;ol&gt;
&lt;li&gt;Insertion&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;push → O(1)：直接新增在最後新增值，不會影響到原本陣列 index&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;unshift→ O(n)：新增第一個 index 的值，會讓後面的 index 都 +1&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;Removal ****→ O(1)：同上，刪除屬性時所耗費的時間一樣&lt;/li&gt;
&lt;/ol&gt;

&lt;ul&gt;
&lt;li&gt;&lt;p&gt;pop→ O(1)：直接移除最後的值，不會影響到原本陣列 index&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;shift→ O(n)：移除第一個 index 的值，會讓後面的 index 都 -1&lt;/p&gt;&lt;/li&gt;
&lt;/ul&gt;

&lt;ol&gt;
&lt;li&gt;&lt;p&gt;Seaching→ O(n)：從第一個 index 開始找，直到找到為止，花費時間與 Array 長度成正比&lt;/p&gt;&lt;/li&gt;
&lt;li&gt;&lt;p&gt;Accessing→ O(1)：同樣使用 Hash Tables，同樣直接取值。 EX：arr[9] 、 arr[999] 花費時間相同。&lt;/p&gt;&lt;/li&gt;
&lt;/ol&gt;

&lt;p&gt;EXAMPLE：&lt;br&gt;
&lt;/p&gt;
&lt;div class="ltag_gist-liquid-tag"&gt;
  
&lt;/div&gt;
&lt;br&gt;
後記：荒廢了大概四個月的部落格，因為確診兵役延期才又有時間來整理筆記，恰好寫面時題時發現事情不太對勁，對於資料結構與演算法還有很多不了解的部分，除了這個主題之外也想要整理一下 typeScrtipt 的筆記，希望自己能夠撐過去!!!

</description>
    </item>
  </channel>
</rss>
