寫在前面的話:
- 迫於業務升級,開始使用 typescript,這裡來了解一下 typescript 的基本型別和泛型的使用。現在 typescript 已經 3.1版本了,非常成熟了。
typeScript 基礎型別
- 下面只介紹一些區別於 JavaScript 的特殊型別
Tuple 元組
- 元組型別允許表示一個已知元素數量和型別的陣列,各元素的型別不必相同。比如,你可以定義一對值分別為 string 和 number 型別的元組。
// Declare a tuple type
let x: [string, number];
// Initialize it
x = [`hello`, 10]; // OK
// Initialize it incorrectly
x = [10, `hello`]; // Error
複製程式碼
enum 列舉
- enum 型別是對 JavaScript 標準資料型別的一個補充。像 C#等其他語言一樣,使用列舉型別可以為一組數值賦予友好的名字。
enum Color {Red, Green, Blue}
let c: Color = Color.Green;
複製程式碼
- 預設情況下,從0開始為元素編號。 你也可以手動的指定成員的數值。 例如,我們將上面的例子改成從 1開始編號:
enum Color {Red = 1, Green, Blue}
let c: Color = Color.Green;
複製程式碼
Any
- 有時候,我們會想要為那些在程式設計階段還不清楚型別的變數指定一個型別。 這些值可能來自於動態的內容,比如來自使用者輸入或第三方程式碼庫。 這種情況下,我們不希望型別檢查器對這些值進行檢查而是直接讓它們通過編譯階段的檢查。 那麼我們可以使用 any型別來標記這些變數:
let notSure: any = 4;
notSure = "maybe a string instead";
notSure = false; // okay, definitely a boolean
複製程式碼
let notSure: any = 4;
notSure.ifItExists(); // okay, ifItExists might exist at runtime
notSure.toFixed(); // okay, toFixed exists (but the compiler doesn`t check)
let prettySure: Object = 4;
prettySure.toFixed(); // Error: Property `toFixed` doesn`t exist on type `Object`.
複製程式碼
Void
- 這玩意一般用在 func 上,剛剛和 Any 相反
function warnUser(): void {
console.log("This is my warning message");
}
//宣告一個void型別的變數沒有什麼大用,因為你只能為它賦予undefined和null:
let unusable: void = undefined
複製程式碼
Null 和 Undefined
- TypeScript裡,undefined和null兩者各自有自己的型別分別叫做undefined和null。 和 void相似,它們的本身的型別用處不是很大:
// Not much else we can assign to these variables!
let u: undefined = undefined;
let n: null = null;
複製程式碼
Never
- never型別表示的是那些永不存在的值的型別。 例如, never型別是那些總是會丟擲異常或根本就不會有返回值的函式表示式或箭頭函式表示式的返回值型別; 變數也可能是 never型別,當它們被永不為真的型別保護所約束時。
// 返回never的函式必須存在無法達到的終點
function error(message: string): never {
throw new Error(message);
}
// 推斷的返回值型別為never
function fail() {
return error("Something failed");
}
// 返回never的函式必須存在無法達到的終點
function infiniteLoop(): never {
while (true) {
}
}
複製程式碼
typescript 泛型
先來談談使用場景
- 模擬一個場景,當我們要使用一個伺服器提供的不同資料,我們需要先建立一箇中介軟體來進行處理(驗證,容錯,糾正),再進行使用。使用 JavaScript 來寫 。
JavaScript
// 模擬服務,提供不同的資料。這裡模擬了一個字串和一個數值
var service = {
getStringValue: function() {
return "a string value";
},
getNumberValue: function() {
return 20;
}
};
// 處理資料的中介軟體。這裡用 log 來模擬處理,直接返回資料當作處理後的資料
function middleware(value) {
console.log(value);
return value;
}
// JS 中對於型別並不關心,所以這裡沒什麼問題
var sValue = middleware(service.getStringValue());
var nValue = middleware(service.getNumberValue());
複製程式碼
typeScript
- 伺服器返回的型別要進行一定的限制
const service = {
getStringValue(): string {
return "a string value";
},
getNumberValue(): number {
return 20;
}
};
複製程式碼
- 為了保證在對 sValue 和 nValue 的後續操作中型別檢查有效,它們也會有型別(如果 middleware 型別定義得當,可以推導,這裡我們先顯示定義其型別)
const sValue: string = middleware(service.getStringValue());
const nValue: number = middleware(service.getNumberValue());
複製程式碼
換成
typescript
的時候我們的中介軟體middleware
,需要返回正確的string
和number
型別。我們需要怎麼做啦?
方法一,特殊型別 any
function middleware(value: any): any{
console.log(value);
return value;
}
複製程式碼
這個方法可以讓最後的型別檢測通過,但是使用
any
的話,致使middleware
就沒有什麼用了。
方法二,多個middleware
function middleware1(value: string): string { ... }
function middleware2(value: number): number { ... }
複製程式碼
- 使用 typescript 的過載(overload)
function middleware(value: string): string;
function middleware(value: number): number;
function middleware(value: any): any {
// 實現一樣沒有嚴格的型別檢查
}
複製程式碼
但是型別過多的話這種方法也不好使。
正解: 使用 typescript 泛型(Generic)
- 先簡單的來說一下什麼是泛型?
- 就是表示一個型別的變數,用他來代替某個實際的型別用於程式設計。
function middleware<T>(value: T): T {
console.log(value);
return value;
}
複製程式碼
middleware
後面緊接的<T>
表示宣告一個表示型別的變數,Value: T
表示宣告引數是T
型別的,後面的: T
表示返回值也是T
型別的。那麼在呼叫middlewre(getStringValue())
的時候,由於引數推匯出來是string
型別,所以這個時候 T 代表了string
,因此此時middleware
的返回型別也就是string
;而對於middleware(getNumberValue())
呼叫來說,這裡的T
表示了number
。
- 如果你使用
vscode
的話,我們預設你已經安裝的支援 typescript 的環境。可以看到我們在推導型別和返回值型別的時候,vscode
會提示你對應的string
和number
的型別。