接上篇。html
1 /*===============================類型斷言======================================*/ 2 /*C#中能夠使用as或者強轉的方法,雖然ts中也有相似的寫法,可是類型斷言 3 只會影響 TypeScript 編譯時的類型,類型斷言語句在編譯結果中會被刪除*/ 4 5 //基接口 6 class Animal { 7 constructor(readonly name: string) { 8 } 9 eat(): void { 10 console.log(`${this.name} is eating`); 11 }; 12 } 13 //子接口們 14 class Dog extends Animal { 15 roar(): void { 16 console.log(`${this.name} is wongwongwong`); 17 }; 18 } 19 class Bird extends Animal { 20 fly(): void { 21 console.log(`${this.name} is flying`); 22 }; 23 } 24 class Fish extends Animal { 25 swim(): void { 26 console.log(`${this.name} is swimming`); 27 }; 28 } 29 //參數使用父類能夠接收全部子類 30 function letsEat(animal: Animal) { 31 animal.eat(); 32 } 33 letsEat(new Dog("小魚")); //小白 is eating 34 35 // 在ts中,父類能夠斷言成子類,由於「狗狗確定是動物」很好理解 36 function dog2Animal(xb: Dog) { 37 (xb as Animal).eat() 38 } 39 40 //函數參數若是使用聯合類型,那麼能夠調用其動物類的方法 41 function letsEat2(animal: Dog | Bird | Fish) { 42 animal.eat(); 43 } 44 letsEat(new Fish("小白")); //小白 is eating 45 46 //那麼想調用子類的方法的話,咱們能夠先進行類型斷言,父類能夠被斷言爲爲子類! 47 //?:那若是animal斷言成Dog,可是animal的實際類型不是Dog,那會怎麼樣呢? 48 function letRoar(animal: Animal) { 49 (animal as Dog).roar(); 50 } 51 function letsFly(animal: Dog | Bird | Fish) { 52 (animal as Bird).fly(); 53 } 54 //結果就是ts編譯沒問題,可是實際運行會報錯 55 //letRoar(new Fish("小魚")); //Error: animal.swim is not a function 56 //letsFly(new Dog("小白")); //Error: animal.fly is not a function 57 58 //解決這個狀況能夠使用intanceof方法先判斷 59 function letsPlay(animal: Dog | Bird | Fish) { 60 if (animal instanceof Dog) { 61 (animal as Dog).roar(); 62 } 63 else if (animal instanceof Bird) { 64 (animal as Bird).fly(); 65 } else if (animal instanceof Fish) { 66 (animal as Fish).swim(); 67 } 68 } 69 letsPlay(new Bird("小鳥")); //小白 is flying 70 71 // 總結(https://ts.xcatliu.com/basics/type-assertion) 72 // (1)聯合類型能夠被斷言爲其中一個類型; 73 // (2)父類能夠被斷言爲子類; 74 // (3)任何類型均可以被斷言爲 any; 75 // (4)any 能夠被斷言爲任何類型; 76 // 總之,若 A 兼容 B,那麼 A 可以被斷言爲 B,B 也能被斷言爲 A 77 // 注意:類型斷言不是類型轉換 78 79 80 /*===============================交叉類型======================================*/ 81 //交叉類型是將多個類型合併成一個類型的意思 82 //例如, Person & Serializable & Loggable 這個類型的對象同時擁有了這三種類型的成員。 83 84 /*for-in語法:能夠遍歷一個對象中的全部屬性,並以字典的讀取方式獲取屬性的值,語法: 85 for (const prop in object) { 86 if (object.hasOwnProperty(prop)) { 87 const element = object[prop]; 88 } 89 } 90 */ 91 92 //如何建立混入的一個方法 93 function extend<T1, T2 extends object>(type1: T1, type2: T2): T1 & T2 { 94 let result = <T1 & T2>{}; 95 96 for (let prop in type1) { 97 (<any>result)[prop] = type1[prop]; 98 } 99 100 for (let prop in type2) { 101 if (type2.hasOwnProperty(prop)) { 102 (<any>result)[prop] = (<any>type2)[prop] 103 104 } 105 } 106 return result; 107 } 108 //在建立一個類類型 109 class Identity { 110 constructor(public gender: string, public birthDay: Date) { 111 } 112 } 113 //將Dog類和Identity類進行交叉 114 let bd: Date = new Date('2015-09-07'); 115 let xb = extend(new Dog("小白"), new Identity("male", bd)); 116 117 console.log(xb.birthDay); //2015-09-07 118 console.log(xb.gender); //male 119 xb.roar(); //小白 is wongwongwong 120 121 122 /*==============================能夠爲null的類型================================*/ 123 //默認狀況下,類型檢查器認爲 null與 undefined能夠賦值給任何類型。 124 //按照JavaScript的語義,TypeScript會把 null和 undefined區別對待 125 126 let s = "foo"; 127 //s = null; // 錯誤, 'null'不能賦值給'string' 128 129 let sn: string | null = "bar"; 130 sn = null; // 能夠 131 132 //sn = undefined; // error, 'undefined'不能賦值給'string | null' 133 134 //對於可爲null類型的參數 135 function f(sn: string | null): string { 136 if (sn == null) { 137 return "default"; 138 } 139 else { 140 return sn; 141 } 142 } 143 /* 「短路運算符」寫法: 144 function f(sn: string | null): string { 145 return sn || "default"; 146 } 147 */ 148 149 150 /*==============================字符串字面量類型================================*/ 151 //字符串字面量:用來約束取值只能是某幾個字符串中的一個。 152 153 type pet = 'dog' | 'bird' | 'fish'; 154 function adoptPet(p: pet): Animal { 155 if (p === 'dog') { 156 return new Dog("小白"); 157 } 158 else if (p === 'bird') { 159 return new Bird("飛飛"); 160 } 161 else if (p === "fish") { 162 return new Fish("金金"); 163 } 164 else { 165 assertNever(p); //這招叫「完整性檢查」,本身體會,驚喜的是,若是前面條件判斷有漏掉某個情形,這裏是會報錯的。 166 } 167 } 168 function assertNever(x: never): never { 169 throw new Error("Unexpected object: " + x); 170 } 171 172 adoptPet("bird"); //輸入的參數只能是「dog」「fish」「bird」之一 173 //adoptPet("cat"); //Error: 傳入其餘值會報錯 174 175 //上面的例子用switch-case寫代碼看起來更清晰簡練一點 176 function adoptPetAgain(s: pet) : Animal { 177 switch (s) { 178 case "dog": return new Dog("小白"); 179 case "bird": return new Bird("飛飛"); 180 case "fish": return new Fish("金金"); 181 default: return assertNever(s); 182 } 183 }