上一篇的小結有提到我會採用 TypeScript 作為開發語言,但是什麼原因要捨棄 JavaScript 呢?我們就來了解一下要如何用 TypeScript 解決幾個 JavaScript 的痛點。
由於網路上已有許多 TypeScript 的資源,本系列文就不再寫基本語法的教學。
JavaScript 是一個弱型別語言,而 TypeScript 可以說是強型別的 JavaScript。在型別上就有以下幾個痛點是可以用 TypeScript 來解決的:
在撰寫帶參數的函式時,不會強制要求參數一定要是何種型別,比如說,有個函式用來將所有參數相加並返回其加總:
const sum = (...args) => args.reduce((a, c) => a + c);
此時很難判斷這個函式究竟是用來加總數字?還是用來字串相加?這兩種結果截然不同,卻都適用於此函式,試想今天是一個大型專案,一個函式多種用法是否很容易產生問題呢?更具體一點的舉例:小明都用 sum(...args)
來處理加總數字、小華都用 sum(...args)
處理字串相加、阿呆都看心情用,這時候可能會有 理解上的誤差 ,當問題產生的時候,就會很難找出錯誤。
const sum = (...args) => args.reduce((a, c) => a + c);
// 都適用於此函式
console.log(sum(1, 2, 3));
console.log(sum(1, 2, '3'));
那麼 TypeScript 如何解決這個問題呢?就是替變數加上型別定義,此時,這個函式只接受數字型別的參數,可以解決理解上的誤差:
const sum = (...args: number[]) => args.reduce((a, c) => a + c);
console.log(sum(1, 2, 3, 4, 5));
// 會顯示錯誤並編譯不過
console.log(sum(1, 2, 3, 4, '5'));
試想今天有一個函式是要處理個人資料用的,所以把個資傳入函式進行處理:
const responseBasicInfo = info => {
// info 裡面有什麼屬性???
};
如上方範例所示,我們無法在第一時間知道這個參數裡面到底有什麼屬性,造成 無法辨識 的問題,這時候只好去看資料庫回傳的資料格式長什麼樣子然後寫 JSDoc...
JSDoc 是一種 JavaScript 的註解風格,部分編輯器可以透過撰寫 JSDoc 來顯示變數的型別
/**
* @param {{ name: string, email: string, phone: string }} info - profile.
*/
const responseBasicInfo = info => {
const { name, email, phone } = info;
console.log(name, email, phone);
};
const profile = {
name: 'HAO',
email: 'test@test.com',
phone: '0987654321'
};
responseBasicInfo(profile);
如果用 TypeScript 的話,可以事先定義好資料的 model,並定義參數的型別為該 model:
class ProfileModel {
public name: string;
public email: string;
public phone: string;
constructor(data) {
this.name = data.name;
this.email = data.email;
this.phone = data.phone;
}
}
const responseBasicInfo = (info: ProfileModel) => {
const { name, email, phone } = info;
console.log(name, email, phone);
};
const profile: ProfileModel = {
name: 'HAO',
email: 'test@test.com',
phone: '0987654321'
};
responseBasicInfo(profile);
在過去,JavaScript 的世界裡是沒有公有與私有概念的,需要用一些手段來實作出私有概念:
這是很常見的「宣告」方式,只要開頭有個 _ 就「當作」私有屬性及方法 ,但其實還是可以被外部使用:
class Pig {
constructor(weight) {
// 問體重不禮貌,所以宣告成私有屬性
this._weight = weight;
}
eat() {
this._weight++;
console.log('Oink!');
}
}
試想被宣告出來的豬會開心嗎?只是我們說好不能偷看而已,但他們的體重還是可以被知道耶!
const shyPig = new Pig(130);
console.log(shyPig._weight); // 130
這樣的宣告方式其實沒有什麼約束力,若團隊中有人誤用的話,那就失去私有的意義了!
確實用閉包可以解決這個問題:
class Pig {
constructor(weight) {
let _weight = weight;
this.eat = () => {
_weight++;
console.log('Oink!');
}
}
}
此時害羞的豬體重只有自己知道:
const shyPig = new Pig(130);
console.log(shyPig._weight); // undefined
但這樣類別的方法有使用到私有屬性的話,就不能在 prototype 中宣告,會造成 程式碼不整潔 的問題。
TypeScript 可以像 C# 等語言一樣直接宣告為 public
、 private
以及 protected
,直觀且存取範圍分明:
class Pig {
private weight: number;
constructor(weight) {
this.weight = weight;
}
public eat() {
this.weight++;
console.log('Oink!');
}
}
const shyPig = new Pig(130);
console.log(shyPig.weight);
在開發大型系統的時候,不論是理解上的落差、無法辨識型別或是存取權,都很容易導致系統產生問題,因此,我會採用 TypeScript 而不是 JavaScript 。下一篇將會帶著大家進入 Express 的世界,敬請期待!