iT邦幫忙

第 11 屆 iT 邦幫忙鐵人賽

DAY 6
1
自我挑戰組

Typescript 初心者手札系列 第 6

【Day 06】TypeScript 資料型別 - 原始型別 (Primitive Types)

前言

閱讀今天的文章前,先回顧一下昨天的學習,回答看看:

  • TypeScript 中有哪些資料型別呢?

如果有點不清楚答案的話,可以看看 Day05 的文章喔!

今天我們要來探討 TS 的原始型別(Primitive Types),包括數字(number)、字串(string)、布林值(boolean)、undefined、null和 symbol,這些型別都是原生JS 的資料型別,在 TS 中也完全支援。

數字(Number)

和 JS 一樣,TypeScript 所有數字都是浮點數,型別為 number,除了支援 10 進制和 16 進制,也支援 ES6 的 2 進制和 8 進制的最新寫法。

let decLiteral: number = 6;
let hexLiteral: number = 0xf00d;

// ES6 中的 2 進制表示法
let binaryLiteral: number = 0b1010;

// ES6 中的 8 進制表示法
let octalLiteral: number = 0o744;
let notANumber: number = NaN;
let infinityNumber: number = Infinity;

轉譯成 ES5 的 JS 後會變成:

var decLiteral = 6;
var hexLiteral = 0xf00d;
// ES6 的 2進制編譯成 10進制數字
var binaryLiteral = 10;

// ES6 的 8進制編譯成 10進制數字
var octalLiteral = 484;
var notANumber = NaN;
var infinityNumber = Infinity;

字串(String)

和JS一樣可以使用雙引號和單引號表示字串

let name1:string = 'bob'
let name2:string = "bob"

轉譯成 ES5 的 JS 後會變成:

var name1 = 'bob'
var name2 = "bob"

TS中也可以使用 ES6 的模板字串(template literal),同樣使用反引號包住字串內容,並透過 $ 嵌入變數

let myName: string = 'Tom'
let myAge: number = 25

let sentence: string = `Hello, my name is ${myName}.
I'll be ${myAge + 1} years old next month.`

轉譯成 ES5 的 JS 後會變成:

var myName = 'Tom';
var myAge = 25;
var sentence = "Hello, my name is " + myName + ".\nI'll be " + (myAge + 1) + " years old next month.";

布林值(Boolean)

即簡單的true/false值。

let isDone: boolean = false

轉譯成 ES5 的 JS 後會變成:

var isDone = false

Undefined 和 Null

和 JS 一樣,在TS 中 undefined 和 null 兩者各自為一資料型別。null 和 undefined 基本上意思都是「無效」的值,但仍有些許不同。

先讓我們先來複習一下 JS 中使用 undefined 和 null的使用差異吧!

undefined - something hasn't been initialized

undefined 意思是變數沒有被宣告,或者是已經宣告了,但是沒有賦值。

常見使用情境如下:
(1)宣告一個變數,但沒有賦值

let a 
console.log(a) //undefined

這時候 a 就會自動被賦值為 undefined

(2) 物件不存在的屬性或陣列不存在的元素

let obj = {}
console.log(obj.foo) //undefined

let arr = []
console.log(arr[0]) //undefined

(3) 函式定義參數,但執行時沒有傳入參數值

//函式定義了參數 a 
function fn(a) {
    console.log(a); // undefined
}
fn(); //執行時未傳入參數值

這時候 a 就是一個原始的、未被賦值的變數

null - something is currently unavailable

null 表示「空值」或「曾經有值但現在沒有了」,使用在宣告了變數,但又不想讓它是未定義的狀態,因此,人為設置此變數為「空值」。

常見使用情境例如:

(1)釋放物件的記憶體內存

let obj = { a: 1, b:2 }
obj = null;     // 釋放物件的記憶體指向
console.log(obj) // null

關於 Null 和 Undefined 在 JS 中的差別可看 stackoverflow這篇解釋有更詳細的說明。

Undefined 和 Null 在 TypeScript 中的使用

let u: undefined = undefined;
let n: null = null;

預設情况下,null 和 undefined 是所有資料型別的的子型別,也就是說,可以把null 和 undefined 賦值給其他型別的變數。

舉個例子來說:

let num: number;
let str: string;

// 可以賦值 null 或 undefined 給其他資料型別如:數字、字串的變數
num = null;
str = undefined;

// Note: 要在 strictNullChecks: false 情況下

但要注意的是,上面程式碼要成立,strictNullChecks 要是 false才行。實際上,預設設定strictNullChecks 是 false,所以預設狀況下不用做調整。

但倘若 strictNullChe存在每種資料型別中(如下圖 null 和 undefined 會獨立出來成為一特殊值)。

這時候,null 只能賦值給 null 和 any,而 undefined 同理,只能賦值給 undefined 和 any (這裡會有一個例外是 undefined 也能賦值給 void)。

let num: number;
num = 123;        // OK
num = null;      // Error
num = undefined; // Error

let str: string;
str = 'Kira';    // OK
str = null;      // Error
str = undefined; // Error

let name: any;
name = undefined // OK 
name = null      // OK

let age: undefined; 
age = undefined  // OK
age = null       // Error 
age = 123        // Error 

let spot: null; 
spot = null      // OK
spot = undefined // Error
spot = 123       // Error 

那 null 和 undefined 在 TypeScript的使用情境是什麼呢?

官網對於 null 和 undefined 的使用情境介紹不多,另外看了一些關於 null 和 undefined 的文件例如 dev.to這篇文章TypeScript Deep Dive,發現在 null 和 undefined 的使用上有各種派別,有些派別使用 null 和 undefined 兩者,有些僅使用 null 或 undefined 其中之一,各有優缺點。

TypeScript 團隊建議只用 undefined 不用 null,Douglas Crockford 認為使用 null 不是一個好主意,應該只用 undefined 就好。然而,要注意的是 JSON 格式只支援 null 不支援 undefined,因此,在處理 JSON 格式的時候可能就需要使用 null。

補充:根據官方 JSON 標準(ECMA-404, Section 5),JSON value 可以是物件、陣列、數字、字串、布林值(true/false)和 null。JSON value 不支援 undefined,所以不能宣告 {“key”:undefined} ,但{“key”:”undefined”} 可被接受因為 ”undefined” 這樣的寫法是字串。

使用情境舉例來說,可以使用複合型別告訴編譯器哪些變數可以是空值

type User = {
  firstName: string;
  lastName: string | undefined;
};

let jane: User = { firstName: "Jane", lastName: undefined };
let john: User = { firstName: "John", lastName: "Doe" };

在填資料時,允許使用者可以不用填姓,可以寫成上方的程式碼。但事實上,在 TS 中更常見的是透過在名稱後方加上?使之成為可選屬性,如此,lastName 屬性就可要可不要。

type User = {
  firstName: string;
  lastName?: string;
};

// 可以放入字串型別的值
let john: User = { firstName: "John", lastName: "Doe" };

// 可以讓值為 undefined 
let jane: User = { firstName: "Jane", lastName: undefined };

// 或者就不要 lastname 這個屬性了
let jake: User = { firstName: "Jake" };

至於之後會介紹的 void 和 null、undefined很相似,之後會再細細比較。

Symbol 符號

symbol的值是透過 Symbol建構函式創建的

let sym1 = Symbol();
let sym2 = Symbol("key"); // 可選字串key

但symbol是不可改變且唯一的

let sym2 = Symbol("key");
let sym3 = Symbol("key");
sym2 === sym3; // false

symbol 可以像字串一樣作為物件屬性的key值

let sym = Symbol();
let obj = {[sym]: "value"};
console.log(obj[sym]); // "value"

除了使用者定義的symbol外,還有一些內建symbols( built-in symbols),用來表示語言內部的行為,列表請參見官網,這邊不多做研究討論。

註:若要使用 symbol,在 tsconfig.json 檔中要設定 lib: ["es2015"],否則會報錯(參考此文章)

小結

今天的文章介紹了 TS 中的原始型別(Primitive Types),包括數字(number)、字串(string)、布林值(boolean)、undefined、null 和 symbol,這些型別都是原生 JS 所支援的。字串、數字和布林值都很常見,Undefined 、 Null 和 Symbol 使用情境較不明確,或許等到之後開始實作應用後可以有更多心得,再來補充分享。

如有錯誤的地方,還請留言告知,我會盡快修改調整,感謝:)

參考資料:
TypeScript官網
Non-Nullable Types in TypeScript
TypeScript Deep Dive
Symbols in JavaScript and TypeScript


上一篇
【Day 05】TypeScript 資料型別 - 總覽
下一篇
【Day 07】TypeScript 資料型別 - 基礎物件型別(Basic Object)
系列文
Typescript 初心者手札30

尚未有邦友留言

立即登入留言