這是第 84 篇不摻水的原創,想獲取更多原創好文,請搜索公衆號關注咱們吧~ 本文首發於政採雲前端博客: 編寫高質量可維護的代碼:Awesome TypeScript
高質量可維護的代碼應具有可讀性高、結構清晰、低耦合、易擴展等特色。而原生的 JavaScript 因爲其弱類型和沒有模塊化的缺點,不利於大型應用的開發和維護,所以,TypeScript 也就應運而生。前端
TypeScript 是 JavaScript 的一個超集,它的設計初衷並非爲了替代 JavaScript,而是基於 JavaScript 作了一系列的加強,包括增長了靜態類型、接口、類、泛型、方法重載等等。因此,只要你有必定的 JavaScript 功底,那麼 TypeScript 上手就很是簡單。而且,你能夠在 TypeScript 中愉快的使用 JavaScript 語法。typescript
接下去,本文將給你們分享下,TypeScript 的重要特性以及在實際場景中的使用技巧,幫助你們更高效的編寫高質量可維護的代碼。編程
JavaScriptjson
TypeScript數組
TypeScript 是靜態類型語言,經過類型註解提供編譯時的靜態類型檢查。安全
通過上述對比,能夠看到 TypeScript 的出現很好的彌補了 JavaScript 的部分設計缺陷,給咱們帶來了很大的便利,也提升了代碼的健壯性和擴展性。閉包
基礎數據類型包括:Boolean、Number、String、Array、Enum、Any、Unknown、Tuple、Void、Null、Undefined、Never。下面選擇幾個 TypeScript 特有的類型進行詳解:編程語言
// 包括 數字枚舉、字符串枚舉、異構枚舉(數字和字符串的混合)。 // 數字枚舉在不設置默認值的狀況下,默認第一個值爲0,其餘依次自增加 enum STATUS { PENDING, PROCESS, COMPLETED, } let status: STATUS = STATUS.PENDING; // 0
Unknown 類型:Unknown 類型也是頂層類型,它能夠接收任何類型,但它與 Any 的區別在於,它首次賦值後就肯定了數據類型,不容許變量的數據類型進行二次變動。因此,在須要接收全部類型的場景下,優先考慮用 Unknown 代替 Any。ide
let tupleType: [string, boolean]; tupleType = ["momo", true];
:
冒號後面註明變量的類型便可。const str: string = 'abc';
應用場景:好比咱們在實現訂單相關功能的時候,須要對訂單進行抽象,定義一個訂單的接口,包括訂單基本信息以及對訂單的相關操做,而後基於這個接口來作進一步的實現。後續若是訂單的相關操做功能有變化,只須要從新定義一個類來實現這個接口便可。模塊化
interface Animal { name: string; getName(): string; } class Monkey implements Padder { constructor(private name: string) { getName() { return 'Monkey: ' + name; } } }
屬性和方法
class Person { // 靜態屬性 static name: string = "momo"; // 成員屬性 gender: string; // 構造函數 constructor(str: string) { this.gender = str; } // 靜態方法 static getName() { return this.name; } // 成員方法 getGender() { return 'Gender: ' + this.gender; } } let person = new Person("female");
getter 和 setter
class Person { private _name: string; get name(): string { return this._name; } set name(newName: string) { this._name = newName; } } let person = new Person('momo'); console.log(person.name); // momo person.name = 'new_momo'; console.log(person.name); // new_momo
繼承
class Animal { name: string; constructor(nameStr=:string) { this.name = nameStr; } move(distanceInMeters: number = 0) { console.log(`${this.name} moved ${distanceInMeters}m.`); } } class Snake extends Animal { constructor(name: string) { super(name); } move(distanceInMeters = 5) { super.move(distanceInMeters); } } let snake = new Snake('snake'); snake.move(); // 輸出:'snake moved 5m'
私有字段
#
字符開頭。私有字段不能在包含的類以外訪問,甚至不能被檢測到。class Person { #name: string; constructor(name: string) { this.#name = name; } greet() { console.log(`Hello, ${this.#name}!`); } } let person = new Person('momo'); person.#name; // 訪問會報錯
泛型接口
interface identityFn<T> { (arg: T): T; }
泛型類
class GenericNumber<T> { zeroValue: T; add: (x: T, y: T) => T; } let myGenericNumber = new GenericNumber<number>(); myGenericNumber.zeroValue = 0; myGenericNumber.add = function (x, y) { return x + y; };
泛型變量
使用大寫字母 A-Z 定義的類型變量都屬於泛型,常見泛型變量以下:
交叉類型就是將多個類型合併爲一個類型。經過 &
運算符定義。以下示例中,將 Person 類型和 Company 類型合併後,生成了新的類型 Staff,該類型同時具有這兩種類型的全部成員。
interface Person { name: string; gender: string; } interface Company { companyName: string; } type Staff = Person & Company; const staff: Staff = { name: 'momo', gender: 'female', companyName: 'ZCY' };
聯合類型就是由具備或關係的多個類型組合而成,只要知足其中一個類型便可。經過 |
運算符定義。以下示例中,函數的入參爲 string 或 number 類型便可。
function fn(param: string | number): void { console.log("This is the union type"); }
類型保護就是在咱們已經識別到當前數據是某種數據類型的狀況下,安全的調用這個數據類型對應的屬性和方法。經常使用的類型保護包括 in
類型保護、typeof
類型保護、instanceof
類型保護和 自定義
類型保護。具體見如下示例:
in
類型保護
interface Person { name: string; gender: string; } interface Employee { name: string; company: string; } type UnknownStaff = Person | Employee; function getInfo(staff: UnknownStaff) { if ("gender" in staff) { console.log("Person info"); } if ("company" in staff) { console.log("Employee info"); } }
typeof
類型保護
function processData(param: string | number): unknown { if (typeof param === 'string') { return param.toUpperCase() } return param; }
instanceof
類型保護:和 typeof
類型用法類似,它主要是用來判斷是不是一個類的對象或者繼承對象的。function processData(param: Date | RegExp): unknown { if (param instanceof Date) { return param.getTime(); } return param; }
自定義
類型保護:經過類型謂詞 parameterName is Type
來實現自定義類型保護。以下示例,實現了接口的請求參數的類型保護。interface ReqParams { url: string; onSuccess?: () => void; onError?: () => void; } // 檢測 request 對象包含參數符合要求的狀況下,才返回 url function validReqParams(request: unknown): request is ReqParams { return request && request.url }
?.
if(result && result.data && result.data.list) // JS if(result?.data?.list) // TS
??
let temp = (val !== null && val !== void 0 ? val : '1'); // JS let temp = val ?? '1'; // TS
不要徹底依賴於類型檢查,必要時仍是須要編寫兜底的防護性代碼。
function fn(value:boolean){ switch(value){ case true: console.log('true'); break; case false: console.log('false'); break; default: console.log('dead code'); } }
// 推薦寫法 function getLocalStorage<T>(key: string): T | null { const str = window.localStorage.getItem(key); return str ? JSON.parse(str) : null; } const data = getLocalStorage<DataType>("USER_KEY");
利用 new() 實現工廠模式
function create<T>(c: { new(): T }): T { return new c(); } class Test { constructor() { } } create(Test);
function fn(arr:readonly number[] ){ let sum=0, num = 0; while((num = arr.pop()) !== undefined){ sum += num; } return sum; }
// 使用 const enum 維護常量 const enum PROJ_STATUS { PENDING = 'PENDING', PROCESS = 'PROCESS', COMPLETED = 'COMPLETED' } function handleProject (status: PROJ_STATUS): void { } handleProject(PROJ_STATUS.COMPLETED)
{ "compilerOptions": { /* 嚴格的類型檢查選項 */ "strict": true, // 啓用全部嚴格類型檢查選項 "noImplicitAny": true, // 在表達式和聲明上有隱含的 any類型時報錯 "strictNullChecks": true, // 啓用嚴格的 null 檢查 "noImplicitThis": true, // 當 this 表達式值爲 any 類型的時候,生成一個錯誤 "alwaysStrict": true, // 以嚴格模式檢查每一個模塊,並在每一個文件里加入 'use strict' /* 額外的檢查 */ "noUnusedLocals": true, // 有未使用的變量時,拋出錯誤 "noUnusedParameters": true, // 有未使用的參數時,拋出錯誤 "noImplicitReturns": true, // 並非全部函數裏的代碼都有返回值時,拋出錯誤 "noFallthroughCasesInSwitch": true,// 報告 switch 語句的 fallthrough 錯誤。(即,不容許 switch 的 case 語句貫穿) } }
TypeScript Extension Pack,它集合了咱們平常經常使用的 TypeScript 相關插件:
Ctrl+Opt+o
,Win/Linux 上快捷鍵 Ctrl+Alt+o
。Ctrl+Opt+V
,Win/Linux 上快捷鍵 Ctrl+Alt+V
。政採雲前端團隊(ZooTeam),一個年輕富有激情和創造力的前端團隊,隸屬於政採雲產品研發部,Base 在風景如畫的杭州。團隊現有 40 餘個前端小夥伴,平均年齡 27 歲,近 3 成是全棧工程師,妥妥的青年風暴團。成員構成既有來自於阿里、網易的「老」兵,也有浙大、中科大、杭電等校的應屆新人。團隊在平常的業務對接以外,還在物料體系、工程平臺、搭建平臺、性能體驗、雲端應用、數據分析及可視化等方向進行技術探索和實戰,推進並落地了一系列的內部技術產品,持續探索前端技術體系的新邊界。
若是你想改變一直被事折騰,但願開始能折騰事;若是你想改變一直被告誡須要多些想法,卻無從破局;若是你想改變你有能力去作成那個結果,卻不須要你;若是你想改變你想作成的事須要一個團隊去支撐,但沒你帶人的位置;若是你想改變既定的節奏,將會是「5 年工做時間 3 年工做經驗」;若是你想改變原本悟性不錯,但老是有那一層窗戶紙的模糊… 若是你相信相信的力量,相信平凡人能成就非凡事,相信能遇到更好的本身。若是你但願參與到隨着業務騰飛的過程,親手推進一個有着深刻的業務理解、完善的技術體系、技術創造價值、影響力外溢的前端團隊的成長曆程,我以爲咱們該聊聊。任什麼時候間,等着你寫點什麼,發給 ZooTeam@cai-inc.com