iT邦幫忙

2023 iThome 鐵人賽

DAY 14
0
Modern Web

TypeScript 魔法 - 喚醒你的程式碼靈感系列 第 14

Day14 - 解開函式型別的神秘面紗

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20230929/201520472WRy9f2HP0.png

什麼是函式型別?

在 TypeScript 中,函式型別用於描述函式的型別,包括函式的參數型別返回型別。它們是一種強大的工具,用於定義函式的形狀,並確保函式的使用方式是正確的。

定義函式型別

我們定義了一個變數 combineValues,但我們並沒有為它指定型別,因此它的型別默認為 any。在 TypeScript 中,如果不明確指定型別,則 TypeScript 將變數的型別設置為 any,這表示它可以存儲任何類型的值。

我們將 add 函式賦值給了 combineValues 變數,這意味著 combineValues 現在引用了 add 函式。

function add(n1: number, n2: number): number {
  return n1 + n2;
}

let combineValues;

combineValues = add;

console.log(combineValues(8, 8)); // 16

由於 combineValuesany 型別,我們嘗試將 combineValues 作為函式執行,而它實際上現在是一個數字。為了避免這種情況,我們需要明確給 combineValues 指定函式型別。

function add(n1: number, n2: number): number {
  return n1 + n2;
}

let combineValues;

combineValues = add;
combineValues = 5;

console.log(combineValues(8, 8));

https://ithelp.ithome.com.tw/upload/images/20230929/20152047YwjCsmNvY9.png

首先,定義 combineValues 型別為 Function 型別,這清楚地表明我們在這裡儲存的任何東西都必須是函式。

function add(n1: number, n2: number): number {
  return n1 + n2;
}

let combineValues: Function;

combineValues = add;
combineValues = 5; // TypeScript 報錯,類型 'number' 不可指派給類型 'Function'

console.log(combineValues(8, 8));

接著,我們嘗試將 printResult 函式也賦值給了 combineValues 變數,可以看到我們沒有得到想要的結果,因為我們在 combineValues 儲存錯誤的函式。

function add(n1: number, n2: number): number {
  return n1 + n2;
}

function printResult(num: number): void {
  console.log(`結果:${num}`); // 結果:17
}

printResult(add(5, 12));

let combineValues: Function;

combineValues = add; // 通過
combineValues = printResult; // 通過

console.log(combineValues(8, 8)); // 結果:8、undefined

首先,函式型別使用箭頭 => 來表示,並包括參數型別和返回型別。我們的目標是確保 combineValues 是一個能夠接受兩個數字並返回一個數字的函式。在這種情況下,add 函式完全符合所定義的函式型別,但是 printResult 函式卻不符合這個定義,導致 TypeScript 產生錯誤。

function add(n1: number, n2: number): number {
  return n1 + n2;
}

function printResult(num: number): void {
  console.log(`結果:${num}`); // 結果:17
}

printResult(add(5, 12));

let combineValues: (a: number, b: number) => number;

combineValues = add; // 通過
combineValues = printResult; // TypeScript 報錯,不符合 combineValues 定義的函式型別

https://ithelp.ithome.com.tw/upload/images/20230929/20152047JHXkbhfISQ.png

介面定義函式形狀

使用 TypeScript 的介面搭配函式使用,這種結合可以稱為函式簽名。介面中的函式簽名用於定義函式的形狀(參數與返回值的型別),然後可以實現這個函式簽名的具體函式。

舉例:

interface Calculator {
  (n1: number, n2: number): number;
}

const add: Calculator = (a, b) => a + b;
const subtract: Calculator = (a, b) => a - b;

console.log(add(5, 3)); // 8
console.log(subtract(5, 3)); // 2

可選參數

與介面的可選屬性類似,我們可以使用 ? 表示可選的參數。這意味著該參數可以在函式調用時省略。

舉例:

function greet(name: string, age?: number): string {
  if (age === undefined) {
    return `我是${name}`;
  } else {
    return `我是${name} - 我今年 ${age} 歲`;
  }
}

const person1 = greet('肉鬆');
console.log(person1); // 我是肉鬆

const person2 = greet('肉鬆', 18);
console.log(person2); // 我是肉鬆 - 我今年 18 歲

特別注意:可選參數必須接在必需參數後面。換句話說,可選參數後面不允許再出現必需參數

function greet(age?: number, name: string): string {
  if (age === undefined) {
    return `我是${name}`;
  } else {
    return `我是${name} - 我今年${age}歲`;
  }
}
// TypeScript 報錯,必要參數不得接在選擇性參數之後

預設參數

當我們希望在函式的參數中設置預設值時,可以使用 TypeScript 的預設參數(Default Parameters)功能。這使得在呼叫函式時,如果未提供特定參數的值,將使用預設值。

舉例:

function greet(name: string = 'Guest'): string {
  return `你好,${name}`;
}

const person1 = greet();
console.log(person1); // 你好,Guest

const person2 = greet('肉鬆');
console.log(person2); // 你好,肉鬆

剩餘參數

在 TypeScript 中,可以使用剩餘參數(Rest Parameters)來處理函式中不定數量的參數。剩餘參數允許我們在函式中接受一個變數數量的參數,這些參數將被收集到一個陣列中。

舉例:

function sum(...rest: number[]): number {
  return rest.reduce((acc, cur) => acc + cur, 0);
}

console.log(sum(1, 2, 3)); // 6
console.log(sum()); // 0,當沒有參數時也可以正常運行

特別注意:剩餘參數必須在函式參數列表的最後

function sum(...rest: number[], n1: number, n2: number): number {
  return rest.reduce((acc, cur) => acc + cur, 0);
}
// TypeScript 報錯,剩餘參數必須是參數清單中的最後一個參數

函式重載

TypeScript 允許我們定義多個具有不同參數數量和型別的函式型別,這稱為函式重載。這在處理不同的輸入情況時非常有用。

舉例:

function greet(name: string): void;
function greet(name: string, age: number): void;

function greet(name: string, age?: number): void {
  if (age === undefined) {
    console.log(`Name: ${name}`);
  } else {
    console.log(`Name: ${name}, Age: ${age}`);
  }
}

greet('肉鬆'); // Name: 肉鬆
greet('傑尼龜', 30); // Name: 傑尼龜, Age: 30

本日重點

  1. 函式型別是一種描述函式的型別。它包括參數型別返回型別
  2. 使用函式型別的語法來宣告函式型別,通常使用箭頭 => 符號。
  3. 表示可選的參數,可選參數後面不允許再出現必需參數
  4. 剩餘參數必須在函式參數列表的最後
  5. 函式重載特性可以定義多個具有不同參數數量和型別的函式型別。

參考


上一篇
Day13 - 解析函式返回型別的精隨
下一篇
Day15 - 解決捉摸不定的資料 - 未知(unknown)
系列文
TypeScript 魔法 - 喚醒你的程式碼靈感30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言