一、any
any型別是沒有任何限制的,一旦變數設定為any等於是把型別檢查關閉了,TS不會去進行校驗,
個人認為既然使用了TS,儘可能還是不要使用any,除非是為了把js專案快速過渡到TS專案,把複雜的型別先用any定義,讓專案能夠快速啟動,但是建議後續還是需要把any重寫成對應的型別
二、unknown
unknown型別是TypeScript 3.0引入的,被稱作安全的any。
unknown型別是安全的,雖然任何值都可以賦給unknown,
但是我們在使用unknown時如果沒有進行型別斷言或基於控制流的型別細化時,unknown不可以賦值給其它型別(除了unknown和any外)
同理,在unknown沒有被斷言或細化到一個確切型別之前,是不允許在其上進行任何操作的。
/* 可以把任何值賦值給unknown,但在使用時需要斷言確定型別:as、typeof 等等 */ let anyName: any = "我是任何呀"; let unknownName: unknown = "我不知道呀"; let myName: string; myName = anyName; // any賦值給其他型別,可以正常編譯 // myName = unknownName; // unknown在沒有斷言前,賦值給其他型別,編譯報錯 myName = unknownName as string; // unknown在這裡斷言為string,可以賦值給string,正常編譯 let unknownNum: unknown; unknownNum = "123"; // 沒有使用前,定義為string,正常編譯 unknownNum = 456; // 沒有使用前,定義為number,正常編譯 let myNum: number; // myNum = unknownNum + 20; // 編譯報錯,因為unknown沒有斷言,TS不知道這是什麼型別 myNum = (unknownNum as number) + 20; // 編譯正常,unknown斷言為number,可以進行加法 // 即使是明確定義了一個物件,但是型別為unknown時,在沒有斷言前還是不能使用物件的方法或屬性 let obj: unknown = { test: '測試屬性' }; // console.log(obj.test); // 報錯,因為unknown沒有斷言,TS不知道這是什麼型別,不允許操作 // 定義一個型別 interface MyObject { test: string; } function printUnknown(unknownObj) { unknownObj as MyObject console.log(unknownObj.test); } printUnknown(obj);
三、never
在TypeScript中,never型別表示那些永不存在的值的型別。它通常用於表示不可到達的程式碼分支或丟擲異常的函式。
never型別表示那些永遠不會發生的型別
例如
當一個函式總是丟擲異常或進入無限迴圈: while(true) {}
或者總是會丟擲異常: function foo() { throw new Error('Not Implemented') }
返回型別就是never.
never型別的應用場景:
- 主要用來進行編譯時的全面的檢查,例如你函式里面的 if else if else 分支,是否已經窮盡了所有可能
- 進行型別校驗
/* 只有never型別本身可以賦值給never型別 */ type reqType = "get" | "post"; function req(method: reqType) { if (method === "get") { console.log("GET 請求"); } else if (method === "post") { console.log("POST 請求"); } else { // 這裡never代表我們已經把所有分支情況都處理了,如果reqType還有一個型別是 'put' 那麼這就會報錯 const rejectMethod: never = method; } }
/* 校驗引數型別 */ function countNum<T>(n: T extends number ? T : never) { return n; } // 這裡可以判斷入參是否為number,如果不是,那麼T就是never,賦值給never就會報錯 countNum(1); // 編譯成功 countNum("a"); // 編譯報錯
四、extends
關鍵字既可以用作類繼承,也可以用作泛型約束。
類繼承中,extends
用於表示類之間的繼承關係:
class Animal { jiao(hour: number) { console.log(`Animal叫了這麼久${hour}h.`); } } class Dog extends Animal { fei() { console.log('wangwang!'); } }
泛型約束中,extends
用於為泛型變數指定型別約束:
function howLong<T extends { length: number }>(arg: T) { console.log(arg.length); } howLong<string>('hello'); // 5 /* 這裡T被約束為具有length屬性的型別,這意味著傳給howLong的引數arg必須有一個length屬性,且其型別為數字。 這裡extends更像是一個判斷條件,用於確保泛型引數型別符合特定的約束。*/
五、keyof
keyof T
是 T
型別的鍵集
/* keyof T 是 T 型別的鍵集 */ interface Home { addr: string; height: string; } type h = keyof Home; // 這裡 h 就等於 "addr" | "height" /* 使用 keyof 進行對映型別,需要注意的是對映型別只能在型別別名(type)中使用,不能在介面中使用 */ interface K { a: number; b: number; } type V1 = { a: number; b: number } // 上面的寫法可以用keyof簡化 type V2 = { [key in keyof K]: number }