iT邦幫忙

2024 iThome 鐵人賽

DAY 17
0
JavaScript

TypeScript 初學者也能看的學習指南系列 第 17

TypeScript 初學者也能看的學習指南 17 - void 型別

  • 分享至 

  • xImage
  •  

https://ithelp.ithome.com.tw/upload/images/20240927/20149362MScbHmacAK.png

本篇要來介紹 void 型別,原本也想把 undefined, null 一起寫在這篇,但怕篇幅過長還是拆開吧!不然閱讀量更低了/images/emoticon/emoticon02.gif

void

在 TypeScript 中,void 通常用於函式沒有回傳值的情況
在 JavaScript 中,函式如果沒有回傳值,會是 undefined。然而,在 TypeScript 中,沒有回傳值不能寫undefined,而是要寫 voidvoidundefined 並不相同

以下兩個函式的回傳值都會被推論為 void

function sayHi() {     // : void
    console.log('Hi!')
} 

function noop() {     // : void
  return;
}

void 中看似合理又不合理的行為

當有一個函式的回傳值被定義為 void,不代表這個函式就禁止不能回傳任何東西
換句話說,它還是可以 return 任何東西,只是會被「忽略」!!

type voidFunc = () => void;
 
const f1: voidFunc = () => {
  return 'hello'; // ✅ Pass,但回傳值會被忽略
};
 
const f2: voidFunc = () => true;  // ✅ Pass,但回傳值會被忽略

在上面的例子中,f1, f2都回傳了不同值,但是 TypeScript 會把回傳值忽略,所以並不會報錯

延續上方範例,將 f2() 的執行結果賦值 test 變數,test 它還是會被推論為 void
就算 f2 函式會回傳 true 也改變不了這個事實
所以這時如果想要使用 test,是會報錯的喔
因為我們沒有辦法使用和依賴一個會被忽略的值

const test = f2(); // : void
if (test) {
  console.log('1') // ❌ An expression of type 'void' cannot be tested for truthiness.
}

為什麼會這樣?

我們知道 TypeScript 是 JavaScript 的超集,JavaScript 在語法上一般是允許函式回傳任何值的,即使你不打算使用它也是一樣。TypeScript 為了兼容這個行為,所以就算回傳在 void 的函式中去寫回傳值,也不會有問題,它只是在告訴編譯器說:「這個函式的回傳值不重要,可以忽略

我們用以下這個範例來再次驗證

type voidFunc = () => void;

const f1: voidFunc = () => {
  return 'hello'; 
};

console.log(f1()) // hello

這個例子印出來的結果是 hello
一開始有點困惑,不是回傳值會被忽略嗎?執行函式時還可以印出東西呀!🤔
後來了解到,能夠印出東西,代表函式有「正常執行」,而「回傳值被忽略」這件事本身並不會去影響函式的運行
TypeScript 中的 void 型別並不會改變 JavaScript 的行為

再來看看這個範例

const src = [1, 2, 3];  // : number[]
const dst = [0];        // : number[]
 
src.forEach((el) => dst.push(el));

forEach() 方法不會有回傳值,所以被推論為 void
https://ithelp.ithome.com.tw/upload/images/20240927/20149362LkA1EhNqzN.png

即使在 callback 中使用了push(),而 push() 會回傳一個數字(代表陣列的長度),但 TypeScript 也不會因為這個回傳值與 void 不符而報錯

函式字面量(literal function)的回傳值為 void

這裡用利用不同範例來對照 void型別的不同結果
我們上面提到回傳值被定義為 void 型別的函式,還是可以 return 任何東西,只是會被「忽略」!!
那這裡是在打自己臉嗎....?

function test1(): void {
  return true;  // ❌ Type 'boolean' is not assignable to type 'void'.
}

const test2 = function (): void {
  return true;  // ❌ Type 'boolean' is not assignable to type 'void'.
};

// ------------ 分隔線 ------------

type voidFunc = () => void;
 
const f1: voidFunc = () => {
  return 'hello'; // ✅ Pass,但回傳值會被忽略
};

function test1test2 都會報錯耶~

這是因為 TypeScript 對「函式字面量」和「函式型別」的處理方式不同

  • 函式字面量
    當使用 function 關鍵字來定義函式時,就被稱為「函式字面量」,範例中的 function test1(): void 就是,當你明確定義一個函式並指定回傳型別為 void 時,TypeScript 會嚴格檢查是否有回傳值,如果有就會報錯

  • 函式型別(函式作為型別的一部分)
    當你定義一個函式型別(如範例中的 type voidFunc = () => void),TypeScript 並不會強制這個函式不能有回傳值,只是會把它忽略而已,就跟文章一開始所說的一樣

void 的指派性(assignability)

https://ithelp.ithome.com.tw/upload/images/20240927/2014936278KxkFLkdW.png
圖片來源
由圖可知,型別定義為 void 的變數可以接收 undefined, any, void, never 的值,在 strictNullChecks 關閉(false) 的狀態下,還可以接收 null 型別

let undefinedVal: undefined;
let anyVal: any;
let nullVal: null;
let voidVal: void;
let neverVal: never = (() => { throw new Error('error') })()
let objectVal: object = { x: 'a'};
let unknownVal: unknown

let res1: void = undefinedVal;  // ✅ Pass
let res2: void = anyVal;        // ✅ Pass
let res3: void = nullVal;    // 在 strictNullChecks 關閉(false)的狀態下才不會報錯
let res4: void = voidVal;       // ✅ Pass
let res5: void = neverVal;      // ✅ Pass
let res6: void = objectVal;  // ❌ Type 'object' is not assignable to type 'void'.
let res7: void = unknownVal; // ❌ Type 'unknown' is not assignable to type 'void'.

總結

在本文中,我們探討了 TypeScript 中的 void 型別、一些看似不合理但實際上是合乎邏輯的行為,以及它在型別系統中的應用

  • void 的用途:主要用於函式沒有回傳值的情況,當函式的回傳值為 void 時,TypeScript 允許函式回傳某些值,但會被忽略

  • 函式字面量 vs 函式型別:當函式被定義為字面量(使用 function 關鍵字)並明確指定回傳 void 時,TypeScript 會嚴格檢查是否有回傳值,並且有則會報錯。而當使用函式型別(如 type voidFunc = () => void),即使回傳了值,TypeScript 也會接受並忽略這個值

  • void 的指派性:void 可以接受來自 undefined、any、void、never 的值,並且在 strictNullChecks 關閉的情況下,還能接受 null。然而,它不能接受 object 和 unknown 型別的值

每天的內容有推到 github 上喔

References


上一篇
TypeScript 初學者也能看的學習指南 16 - unknown 未知型別
下一篇
TypeScript 初學者也能看的學習指南 18 - undefined、null 型別
系列文
TypeScript 初學者也能看的學習指南30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

1 則留言

0
Mao
iT邦研究生 5 級 ‧ 2024-09-28 00:11:32

我觀察到閱讀量跟發文時間點關係蠻大的~
22:00~12:00 這區間出的文章閱讀量都會比較低
加油!
/images/emoticon/emoticon12.gif

hannnahTW iT邦新手 1 級 ‧ 2024-09-28 02:25:24 檢舉

原來如此~我很常壓線發文哈哈🤣
謝謝你!一起加油~

我要留言

立即登入留言