<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
最近完整地看了一遍TypeScript
的官方檔案,發現檔案中有一些知識點沒有專門講解到,或者是講解了但卻十分難以理解,因此就有了這一系列的文章,我將對沒有講解到的或者是我認為難以理解的知識點進行補充講解,希望能給您帶來一點幫助。
tips:配合官方檔案食用更佳
這是本系列的第二篇TypeScript中extends的正確開啟方式,在TypeScript
中我們經常見到extends
這一關鍵字,我們可能第一時間想到的就是繼承,但除了繼承它其實還有其他的用法,接下來讓我們來一一獲得extends
的正確開啟方式。
作為眾人皆知的extends
關鍵字,其最出名的使用方式便是繼承。
首先讓我們來用extends
實現一下類的繼承。
class Animal { public name; constructor(name: string) { this.name = name; } eat(food: string) { console.log(`${this.name}正在吃${food}`); } } class Sheep extends Animal { constructor(name: string) { super(name); } miemie() { console.log("別看我只是一隻羊,羊兒的聰明難以想象~"); } } let lanyangyang = new Sheep("懶羊羊"); lanyangyang.eat("青草蛋糕"); // 懶羊羊正在吃青草蛋糕 lanyangyang.miemie(); //別看我只是一隻羊,羊兒的聰明難以想象~
首先我們定義了一個Animal
類,該類有name
屬性以及eat
方法。然後又定義了一個繼承Animal
類的Sheep
類,該類在父類別name
屬性以及eat
方法基礎上又新增了一個miemie
方法。
extends
不僅能夠用於類與類之間的繼承上,還能夠用於介面與介面之間的繼承。接下來我們來實現一下介面之間的繼承。
interface IAnimal{ name:string; eat:(food:string)=>void; } interface ISheep extends IAnimal{ miemie:()=>void; } let lanyangyang:ISheep={ name:'懶羊羊', eat(food:string){ console.log(`${this.name}正在吃${food}`); }, miemie() { console.log("別看我只是一隻羊,羊兒的聰明難以想象~"); } } lanyangyang.eat("青草蛋糕"); // 懶羊羊正在吃青草蛋糕 lanyangyang.miemie(); //別看我只是一隻羊,羊兒的聰明難以想象~
我們定義了一個IAnimal
介面,然後用通過extends
繼承IAnimal
定義了ISheep
介面,則實現ISheep
介面的變數lanyangyang
必須要有父介面的name
屬性以及實現eat
方法,並且還要實現本身的miemie
方法。
現在我們通過extends
實現了類與類之間的繼承、介面與介面之間的繼承,那麼類與介面之間是否能互相繼承呢?答案是可以。
首先我們使用extends
來實現介面繼承類。
class Animal { public name; constructor(name: string) { this.name = name; } eat(food: string) { console.log(`${this.name}正在吃${food}`); } static run(){ console.log(`${this.name} is running`) } } interface ISheep extends Animal{ miemie:()=>void; } let lanyangyang:ISheep={ name:'懶羊羊', eat(food:string){ console.log(`${this.name}正在吃${food}`); }, miemie() { console.log("別看我只是一隻羊,羊兒的聰明難以想象~"); } } lanyangyang.eat("青草蛋糕"); // 懶羊羊正在吃青草蛋糕 lanyangyang.miemie(); //別看我只是一隻羊,羊兒的聰明難以想象~
在介面繼承類時,可以把類看作一個介面,但是類中的靜態方法是不會繼承過來的。我們在實現ISheep
介面的變數lanyangyang
必須要有類Animal
的name
屬性以及實現eat
方法,並且還要實現本身的miemie
方法。但是我們不必實現類Animal
的靜態方法run
。
是不是覺得還會有下一個標題類繼承介面
,對不起,這個真沒有!類繼承介面使用的關鍵字變成了implements
。
extends
還有一個比較常見的用法就是在三元表示式中進行條件判斷,即判斷一個型別是否可以分配給另一個型別。這裡根據三元表示式中是否存在泛型判斷結果還不一致,首先我們介紹普通的三元表示式條件判斷。
帶有extends
的三元表示式如下:
type TypeRes=Type1 extends Type2? Type3: Type4;
這裡表達的意思就是如果型別Type1
可被分配給型別Type2
,則型別TypeRes
取Type3
,否則取Type4
。那怎麼理解型別Type1
可被分配給型別Type2
呢??
我們可以這樣理解:型別為Type1
的值可被賦值給型別為Type2
的變數。可以具體分為一下幾種情況:
Type1
和Type2
為同一種型別。Type1
是Type2
的子型別。Type2
型別相容型別Type1
。 接下來我們分情況進行驗證。Type1
和Type2
為同一種型別。type Type1=string; type Type2=Type1; type Type3=true; type Type4=false; type TypeRes=Type1 extends Type2? Type3: Type4; // true
這裡Type1
和Type2
為同一種型別。因此Type1
可被分配給Type2
。因此TypeRes
型別最後取為true
。
Type1
是Type2
的子型別。class Animal { public name; constructor(name: string) { this.name = name; } eat(food: string) { console.log(`${this.name}正在吃${food}`); } } class Sheep extends Animal { constructor(name: string) { super(name); } miemie() { console.log("別看我只是一隻羊,羊兒的聰明難以想象~"); } } type Type1=Sheep; type Type2=Animal; type Type3=true; type Type4=false; type TypeRes=Type1 extends Type2? Type3: Type4; // true
這裡Sheep
類繼承自Animal
,即Type1
是Type2
的子型別。因此Type1
可被分配給Type2
。因此TypeRes
型別最後取為true
。
Type2
型別相容型別Type1
。首先還是丟擲一個問題,什麼是型別相容
??這個問題可以從官方檔案中得到答案,大家可以戳型別相容性詳細瞭解!
所謂 Type2
型別相容型別Type1
,指得就是Type1
型別的值可被賦值給型別為Type2
的變數。 舉個栗子:
type Type1={ name:string; age:number; gender:string; } type Type2={ name:string; age:number; } type Type3=true; type Type4=false; type TypeRes=Type1 extends Type2? Type3: Type4; // true
由於型別Type1
擁有至少與Type2
相同的屬性,因此Type2
是相容Type1
的。也就是說Type1
型別的值可被賦值給型別為Type2
的變數。
let kenny1:Type1={ name:'kenny', age:26, gender:'male' } let kenny2:Type2=kenny; // no Error
因此TypeRes
型別最後取為true
。
再舉個栗子,以函數的相容性為例,
type Type1=(a:number)=>void; type Type2=(a:number,b:string)=>void; type Type3=true; type Type4=false; type TypeRes=Type1 extends Type2? Type3: Type4; // true
當函數引數不同時,看Type2
是否相容Type1
,就要看Type1
的每個引數必須能在Type2
裡找到對應型別的引數。 注意的是引數的名字相同與否無所謂,只看它們的型別。
這裡Type1
第一個number
型別的引數是可以在Type2
中找到,即Type1
型別的函數可被賦值給型別為Type2
的變數。
let fn1:Type1=(a:number)=>{} let kenny2:Type2=fn1; // no Error
因此TypeRes
型別最後取為true
。
我們先來一個舉一個不帶泛型的栗子,大家可以想想結果是什麼。
type Type1=string|number; type Type2=string; type Type3=true; type Type4=false; type TypeRes=Type1 extends Type2? Type3: Type4;
沒錯,由於Type1
是Type2
的父類別型,因此Type1
是不可分配給Type2
的,因此TypeRes
型別最後取為false
。
但當我們加上泛型之後呢,再來看一個栗子。
type Type1=string|number; type Type2=string; type Type3=true; type Type4=false; type Type5<T>=T extends Type2? Type3: Type4; type TypeRes<Type1> // boolean
這裡TypeRes
型別最後就不是false
了,而變成boolean
。這是為什麼呢?
原來再使用泛型時,若extends左側的泛型具體取為一個聯合型別時,就會把聯合型別中的型別拆開,分別帶入到條件判斷式中進行判斷,最後把結果再進行聯合。上述的栗子中結果可以這麼來看,
(string extends string?true:false)|(number extends string?true:false) true | false boolean
在高階型別中有很多型別實現便用到了這一特性。
比如Exclude<T, U>
-- 從T
中剔除可以賦值給U
的型別。
type T1 = "a" | "b" | "c" | "d"; type T2 = "a" | "c" | "f" type ExcludeT1T2=Exclude<T1,T2> //"b"|"d"
該型別的型別實現為
type Exclude<T, U> = T extends U ? never : T;
當T
為聯合型別時,會自動分發條件,對T
中的所有型別進行遍歷,判斷其是否可以分配給型別U
,如果是的話便返回never
型別,否則返回其原來的型別。最後再將其進行聯合得到一個結果聯合型別。
由於never
型別與其他型別聯合最終得到的還是其他型別,因此便可以從型別T中剔除掉可以賦給U的型別。
那有沒有辦法讓泛型三元表示式中extends
和普通的extends
作用相同?有!只需要給泛型加一個[]
。栗子如下:
type Type1=string|number; type Type2=string; type Type3=true; type Type4=false; type Type5<T>=[T] extends Type2? Type3: Type4; type TypeRes<Type1> // false
首先我們來回答一下什麼是泛型?簡單來說,泛型就是一種型別變數,普通的變數代表一個任意的值,而不是一個特定的值,我們可以把任何值賦給變數,而型別變數代表一個任意的型別,而不是一個特定的型別,我們可以把任何型別賦給型別變數。它是一種特殊的變數,只用於表示型別而不是值。
那如果我們不想讓泛型表示任意型別時,該怎麼辦?這時我們就可以使用extends
對泛型進行約束,讓泛型表示滿足一定條件的型別。接下來,我們使用extends
進行泛型的約束。
interface ISheep{ name:string; eat:(food:string)=>void; miemie:()=>void; } function eatAndMiemie<T extends ISheep>(sheep:T):void{ sheep.eat("青草蛋糕"); sheep.miemie(); } eatAndMiemie( { name: "懶羊羊", eat(food:string){ console.log(`${this.name}正在吃${food}`); }, miemie() { console.log("別看我只是一隻羊,羊兒的聰明難以想象~"); } run() {console.log(`${this.name}正在奔跑`)}; } ) // 懶羊羊正在吃青草蛋糕 //別看我只是一隻羊,羊兒的聰明難以想象~
這裡我們便對泛型T
進行了約束,其必須至少要擁有ISheep
的name
屬性及eat
、miemie
方法,另外T
中若有其他的屬性及方法,則不作限制。這裡我們便通過extends
對泛型T
進行了約束。
其實泛型約束中的extends
也是起到了三元表示式中型別分配的作用,其中T extends ISheep
表示泛型T
必須可以分配給型別Isheep
。
以上就是TypeScript中extends的正確開啟方式詳解的詳細內容,更多關於TypeScript extends開啟方式的資料請關注it145.com其它相關文章!
相關文章
<em>Mac</em>Book项目 2009年学校开始实施<em>Mac</em>Book项目,所有师生配备一本<em>Mac</em>Book,并同步更新了校园无线网络。学校每周进行电脑技术更新,每月发送技术支持资料,极大改变了教学及学习方式。因此2011
2021-06-01 09:32:01
综合看Anker超能充系列的性价比很高,并且与不仅和iPhone12/苹果<em>Mac</em>Book很配,而且适合多设备充电需求的日常使用或差旅场景,不管是安卓还是Switch同样也能用得上它,希望这次分享能给准备购入充电器的小伙伴们有所
2021-06-01 09:31:42
除了L4WUDU与吴亦凡已经多次共事,成为了明面上的厂牌成员,吴亦凡还曾带领20XXCLUB全队参加2020年的一场音乐节,这也是20XXCLUB首次全员合照,王嗣尧Turbo、陈彦希Regi、<em>Mac</em> Ova Seas、林渝植等人全部出场。然而让
2021-06-01 09:31:34
目前应用IPFS的机构:1 谷歌<em>浏览器</em>支持IPFS分布式协议 2 万维网 (历史档案博物馆)数据库 3 火狐<em>浏览器</em>支持 IPFS分布式协议 4 EOS 等数字货币数据存储 5 美国国会图书馆,历史资料永久保存在 IPFS 6 加
2021-06-01 09:31:24
开拓者的车机是兼容苹果和<em>安卓</em>,虽然我不怎么用,但确实兼顾了我家人的很多需求:副驾的门板还配有解锁开关,有的时候老婆开车,下车的时候偶尔会忘记解锁,我在副驾驶可以自己开门:第二排设计很好,不仅配置了一个很大的
2021-06-01 09:30:48
不仅是<em>安卓</em>手机,苹果手机的降价力度也是前所未有了,iPhone12也“跳水价”了,发布价是6799元,如今已经跌至5308元,降价幅度超过1400元,最新定价确认了。iPhone12是苹果首款5G手机,同时也是全球首款5nm芯片的智能机,它
2021-06-01 09:30:45