Skip to main content

Command Palette

Search for a command to run...

TypeScript - Array

Updated
•View as Markdown

學習資源:

Codecademy

介紹

陣列與使用 primitive 型別有點不同。這是因為陣列通常包含許多資料。追蹤陣列的型別意味著跟蹤每個元素的型別。 例如:

let firstArray = [1, 2, 3, 4];
let secondArray =  [5, '6', [7]];

我們可以看到,firstArray的元素都是number 型別。 另一方面,secondArray具有不同型別的元素:number、string 和 array。兩者都是 JavaScript 陣列的例子。

以下的例子示範說,假如我們不用 TypeScript 的話要怎麼做這些型別的檢查:

let customersArray = ['Custy Stomer', 'C. Oostomar', 'C.U.S. Tomer', 3432434, 'Custo Mer', 'Custopher Ustomer', 3432435, 'Kasti Yastimeur'];

//Write Your Code here:
function checkCustomersArray(){
  for(let i=0; i<customersArray.length; i++){
      if(typeof customersArray[i] != 'string'){
        console.log(`Type error: ${customersArray[i]} should be a string!`);
      }
  }
}
checkCustomersArray()

function stringPush(val){
  if(typeof val === 'string'){
    customersArray.push(val);
  } 
}

Array Type Annotations 陣列註釋

陣列型別的型別註釋相當簡單:把 [] 放在元素型別之後。在以下的程式中,names 是一個只能包含字串的陣列:

let names: string[] = ['Danny', 'Samantha'];

另一種方法是使用 Array<T>,其中T代表型別。

let names: Array<string> = ['Danny', 'Samantha'];

而正如我們預期的那樣,如果我們嘗試將數字陣列 assign 給字串陣列的變數,就會收到型別錯誤的訊息:

let names: string[] = [1,2,3]; // Type Error!

而當陣列的方法有操作不同型別的元素時,也會跳出錯誤。

let names: string[] = ['Damien'];
names.push(666) // Type Error!

Multi-dimensional Arrays 多維陣列註釋

除了以上一維的陣列結構,事實上我們也可以做多維的陣列結構:

let arr: string[][] = [['str1', 'str2'], ['more', 'strings']];

空陣列 [] 與任何陣列型別相容:

let names: string[] = []; // No type errors.
let numbers: number[] = []; // No type errors.
names.push('Isabella');  
numbers.push(30);

Tuples 元組

如我們所知道的,JavaScript 陣列可以靈活的容納不同型別的元素。而使用TypeScript,我們還可以定義具有固定型別序列的陣列:

let ourTuple: [string, number, string, boolean] = ['Is', 7 , 'our favorite number?' , false];

在 TypeScript 中,當一個陣列用特定型別的元素進行型別時,被稱為元組。元組型別指定相容元組的長度和順序,如果不滿足以下任何一個條件,將導致錯誤:

let numbersTuple: [number, number, number] = [1,2,3,4]; // Type Error! numbersTuple should only have three elements.
let mixedTuple: [number, string, boolean] = ['hi', 3, true] // Type Error! The first elements should be a number, the second a string, and the third a boolean.

就 JavaScript 而言,元組就像陣列一樣。它們都有 .length 屬性。我們可以使用 [index] 訪問(或更改)兩者的元素。但是,儘管它們相似,但元組和陣列在TypeScript 中並沒有相容的型別。具體來說,我們無法為元組變數 assign 陣列元素,即使元素型別正確:

let tup: [string, string] = ['hi', 'bye'];
let arr: string[] = ['there','there'];
tup = ['there', 'there']; // No Errors.
tup = arr; // Type Error! An array cannot be assigned to a tuple.

Array Type Inference 陣列型別推論

TypeScript 可以從初始值和返回值中推斷變數型別。但即便如此,我們可能還不知道在處理陣列時到底要期待什麼來推論型別。

let examAnswers= [true, false, false];

它似乎同樣可能是 boolean[] or [boolean, boolean, boolean] 。實際上,他會是 boolean[]。

examAnswers[3] = true; // No type error.

由於元組有固定長度,我們無法向元組新增額外的 boolean 元素:

let tupleOfExamAnswers: [boolean, boolean, boolean] = [true, false, false];
tupleOfExamAnswers[3] = true; // Type error! The tuple only has 3 elements.

而當我們使用 .concat() 方法時,我們也會得到同樣的型別推論:

let tup: [number, number, number] = [1,2,3];
let concatResult = tup.concat([4,5,6]); // concatResult has the value [1,2,3,4,5,6].

在上面的程式中,TypeScript 會將變數 concatResult 推斷為數字陣列,而不是元組。

Rest Parameters

將型別 assign 給 rest parameters 類似於將型別 assign 給陣列。以下是沒有型別的 rest parameters 範例:

function smush(firstString, ...otherStrings){
  let output = firstString;
  for(let i = 0; i < otherStrings.length; i++){
    output = output.concat(otherStrings[i]);
  }
  return output;
}

以下是上面程式的結果:

smush('a','h','h','H','H','H','!','!'); // Returns: 'ahhHHH!!'.

但就像大家知道的,這樣的方式並不安全,如果使用 smush(1,2,3) 的話,就會出錯。所以為了確保型別,可以向以下這樣:

function smush(firstString, ...otherStrings: string[]){
  /*rest of function*/
}

Spread Syntax

以下是一個沒有使用元組的應用:

function gpsNavigate(startLatitudeDegrees:number, startLatitudeMinutes:number, startNorthOrSouth:string, startLongitudeDegrees: number, startLongitudeMinutes: number, startEastOrWest:string, endLatitudeDegrees:number, endLatitudeMinutes:number , endNorthOrSouth:string, endLongitudeDegrees: number, endLongitudeMinutes: number,  endEastOrWest:string) {
  /* navigation subroutine here */
}
let codecademyCoordinates: [number, number, string, number, number, string] = [40, 43.2, 'N', 73, 59.8, 'W'];
let bermudaTCoordinates: [number, number, string, number, number, string] = [25, 0 , 'N' , 71, 0, 'W'];
gpsNavigate(...codecademyCoordinates, ...bermudaTCoordinates);
// And by the way, this makes the return trip really convenient to compute too:
gpsNavigate(...bermudaTCoordinates, ...codecademyCoordinates);
// If there is a return trip . . .

More from this blog

Learn Next.js 官方教學筆記 - Chapter 9: Streaming

此系列為 Next.js 官方教學 Learn Next.js 的筆記。 文章連結:Chapter 9: Streaming 在前一個章節,已經讓 dashboard 的頁面可以動態更新資料,並且,也討論了緩慢的 data fetching 過程會如何影響網站的效能。那接下來再來討論看看當有這樣子緩慢的 data fetching 時,要如何改善使用者體驗。 在這一章節可以學到以下幾個項目: 什麼是 streaming?以及要如何使用它? 要怎麼用 streaming 實作 loading....

Apr 4, 2024

Learn Next.js 官方教學筆記 - Chapter 8: Static and Dynamic Rendering

此系列為 Next.js 官方教學 Learn Next.js 的筆記。 文章連結:Chapter 8: Static and Dynamic Rendering 在上一個章節中,幫 Dashboard Overview page fetch 了相關資料。然而,我們要討論現在設定下的兩個限制: 現在的 data request 會造成 waterfall。 目前 dashboard 是 Static,所以任何資料的更新都沒辦法顯示在畫面上。 在這一章節可以學到以下幾個項目: 什麼是 st...

Apr 2, 2024

Learn Next.js 官方教學筆記 - Chapter 7: Fetching Data

此系列為 Next.js 官方教學 Learn Next.js 的筆記。 文章連結:Chapter 7: Fetching Data 上一章節 Setting Up Your Database,主要在教你把專案 push 到 GitHub 上並且利用 Vercel 部署以及建立 database 的步驟,因為蠻清楚的,所以就不多說明。 而現在我們已經建立好了 database。接下來就來討論要如何使用不同方法來 fetch 資料,並且呈現在 dashboard 的概覽上。 在這一章節可以學到以...

Apr 1, 2024

Learn Next.js 官方教學筆記 - Chapter 5 : Navigating Between Pages

此系列為 Next.js 官方教學 Learn Next.js 的筆記。 文章連結:Chapter 5 : Navigating Between Pages。 在前一個章節,我們建立了 dashboard 的 layout 以及 pages。 現在要來新增一些連結讓使用者可以在 dashboard routes 間作切換。 在這一章節可以學到以下幾個項目: 怎麼使用 next/link 元件。 怎麼使用 usePathname() hook 來顯示 active link。 navigati...

Mar 30, 2024

My name is Vince.

12 posts

Hi ! 我是 Vince