(二)typescript之型別檢查
阿新 • • 發佈:2021-07-05
一、基本型別檢查
1.型別約束可以約束變數、函式引數、函式返回值
1 let age: number = 18; 2 age = 19; 3 function sum(a: number, b: number): number { 4 return a+b; 5 } 6 let num:number = sum(3, 4);
tips:使用快捷鍵f2可以重新命名函式,快捷鍵f12可以快速跳轉至函式定義
2.基本資料型別和引用資料型別的型別約束
1 // 數字型別 2 let age: number = 18; 3 // 布林型別 4 let flag: boolean = true; 5 // 字串型別 6 let name: string = 'pengyuyan'; 7 // null 8 let nullValue: null = null; 9 // undefined 10 let undefinedValue: undefined = undefined; 11 // object 12 let obj: object = {}; 13 // 陣列型別 14 let nums1: number[] = [1,2,3]; 15 let nums2: Array<number> = [3,4,5];
tips: undefined和null預設可以賦值給任意型別,若需要使用更嚴格的空型別檢查,需要在tsconfig新增配置:strictNullChecks: true
3.其他常用型別
1 // 聯合型別 2 let name: string | undefined = undefined; 3 // void 約束函式返回值,表示該函式沒有任何返回 4 function print(): void { 5 console.log(111) 6 } 7 // never 約束函式返回值,表示該函式永遠不可能結束 8 function throwError(msg: string): never { 9 throw new Error(msg); 10 } 11 // 字面量型別 使用一個值進行約束 12 let gender: "男" | "女";13 gender = "男"; 14 let user: { 15 name: string 16 age: number 17 } 18 // 元祖型別(Tuple) 一個固定長度的陣列,並且陣列中的每一項的型別確定 19 let tu: [string, number]; 20 tu = ["3", 4]; 21 // any型別 any型別可以繞過型別檢查,any型別的資料可以賦值給任意型別。 22 let data: any = "asaass"; 23 let num: number = data;
4.函式相關約束
(1)函式過載
圖片
對於上圖中的result1,我們理想得到的結果應該是這樣的:如果兩個引數都是數字型別,那麼推斷出的返回結果也應該是數字型別;兩個引數是字串時,同理。
但兩個引數都是數字型別時,圖中推斷的返回值卻是string | number型別,怎樣讓它能正確推斷出返回值是number型別呢?這就需要藉助函式過載來實現啦
1 // 表示兩個引數都是number型別時,返回值為number型別 2 function combine(a: number, b: number): number; 3 // 表示兩個引數都是string型別時,返回值為string型別 4 function combine(a: string, b: string): string; 5 function combine(a: number | string, b: number | string) 6 : number | string { 7 if (typeof a === 'number' && typeof b === 'number') { 8 return a * b; 9 } else if (typeof a === 'string' && typeof b === 'string') { 10 return a + b; 11 } 12 throw new Error('a和b必須是相同的型別'); 13 } 14 // 這樣的話result1就推斷出是number型別,result2則是string型別的 15 const result1 = combine(3, 3); 16 const result2 = combine('3', '3');
(2)可選引數
1 // 表示第2、3個引數可填可不填,且必須在引數列表的末尾 2 function sum(a: number, b?:number, c?:number) { 3 } 4 sum(1, 2, 3); 5 sum(1);
二、擴充套件型別
1.類型別名
1 // type關鍵字 + 名字 = xxx 2 type Gender = "男" | "女" 3 type User = { 4 name: string 5 age: number 6 gender: Gender 7 } 8 function getUsers(g:Gender):User[] { 9 return []; 10 } 11
2.列舉
列舉通常用於約束某個變數的取值範圍
字面量和聯合型別配合使用,也可以達到同樣的目標
但是使用字面量型別時會有以下的問題:
1 // 型別約束的位置,會產生重複的程式碼 2 let gender: 'man' | 'female' 3 gender = 'man'; 4 function getUsers(g: 'man' | 'female') { 5 // do() 6 }
可使用類型別名解決以上問題
1 type Gender = 'man' | 'female' 2 let gender: Gender = 'man'; 3 function getUsers(g: Gender) { 4 // do() 5 } 6
但是類型別名也會有另外的問題
問題一:邏輯名稱和真實的值產生了混淆,會導致當修改真實值的時候,產生大量的修改
1 // man和female可能還會有很多種不同的取值,比如“男”“女”,“帥哥”“美女”,但它們的 2 // 邏輯含義其實都是一樣的,但是賦值的時候只能賦真實的值,所以一旦真實值換種寫法, 3 // 就會導致大量的真實值的更改 4 type Gender = 'man' | 'female' 5 let gender: Gender = 'man'; 6 let gender1: Gender = 'man'; 7 let gender2: Gender = 'female';
1 type Gender = '男' | '女' 2 let gender: Gender = '男'; 3 let gender1: Gender = '男'; 4 let gender2: Gender = '女';
問題二:型別不會進入編譯結果無法檢視Gender的具體值有哪些
圖片
可使用列舉解決以上問題
1 // 修改真實值,只需要修改列舉值,不用修改大量真實值 2 enum Gender { 3 male = "男", 4 female = "女", 5 } 6 let gender: Gender = Gender.male; 7 let gender1: Gender = Gender.male; 8 let gender2: Gender = Gender.female; 9 // 可以直接訪問列舉值 10 console.log('Gender: ', Gender);
列舉的規則
(1)列舉的值可以為字串或者數字
1 // 若第一個列舉值為數字,後面的值會自動自增 2 enum Level { 3 level1 = 2, 4 level2, 5 level3, 6 } 7 let l2: Level = Level.level2; 8 let l3: Level = Level.level3; 9 console.log('l2: ', l2);// 3 10 console.log('l3: ', l3);// 4 11 // 若沒有設定值,則第一個預設值為0,後面值依次遞增 12 enum Level { 13 level1, // 0 14 level2, // 1 15 level3, // 2 16 } 17
(2)字串列舉和數字列舉的編譯結果不同
1 // 字串列舉 2 enum Gender { 3 male = "男", 4 female = "女", 5 } 6 console.log('Gender: ', Gender); 7 // 數字列舉 8 enum Level { 9 level1 = 2, 10 level2, 11 level3, 12 } 13 console.log('Level: ', Level);
列印結果為:
圖片
使用列舉時需要注意:
儘量不要再一個列舉中既出現字串欄位,又出現數字欄位
1 // ❌ 不建議 2 enum Level { 3 level1 = 2, 4 level2 = "a", 5 }
使用列舉時,儘量使用列舉的名稱,而不使用真實的值
1 function getUsers(l: Level.level1) { 2 3 } 4 getUsers(Level.level1);