欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

TypeScript中extends的正確打開方式詳解

 更新時(shí)間:2022年08月22日 10:52:15   作者:kennyshaw  
這篇文章主要為大家介紹了TypeScript中extends的正確打開方式詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪

前言

最近完整地看了一遍TypeScript的官方文檔,發(fā)現(xiàn)文檔中有一些知識(shí)點(diǎn)沒有專門講解到,或者是講解了但卻十分難以理解,因此就有了這一系列的文章,我將對(duì)沒有講解到的或者是我認(rèn)為難以理解的知識(shí)點(diǎn)進(jìn)行補(bǔ)充講解,希望能給您帶來一點(diǎn)幫助。

tips:配合官方文檔食用更佳

這是本系列的第二篇TypeScript中extends的正確打開方式,在TypeScript中我們經(jīng)常見到extends這一關(guān)鍵字,我們可能第一時(shí)間想到的就是繼承,但除了繼承它其實(shí)還有其他的用法,接下來讓我們來一一獲得extends的正確打開方式。

extends第一式:繼承

作為眾人皆知的extends關(guān)鍵字,其最出名的使用方式便是繼承。

類繼承類

首先讓我們來用extends實(shí)現(xiàn)一下類的繼承。

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();
//別看我只是一只羊,羊兒的聰明難以想象~

首先我們定義了一個(gè)Animal類,該類有name屬性以及eat方法。然后又定義了一個(gè)繼承Animal類的Sheep類,該類在父類name屬性以及eat方法基礎(chǔ)上又新增了一個(gè)miemie方法。

接口繼承接口

extends不僅能夠用于類與類之間的繼承上,還能夠用于接口與接口之間的繼承。接下來我們來實(shí)現(xiàn)一下接口之間的繼承。

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();
//別看我只是一只羊,羊兒的聰明難以想象~

我們定義了一個(gè)IAnimal接口,然后用通過extends繼承IAnimal定義了ISheep接口,則實(shí)現(xiàn)ISheep接口的變量lanyangyang必須要有父接口的name屬性以及實(shí)現(xiàn)eat方法,并且還要實(shí)現(xiàn)本身的miemie方法。

現(xiàn)在我們通過extends實(shí)現(xiàn)了類與類之間的繼承、接口與接口之間的繼承,那么類與接口之間是否能互相繼承呢?答案是可以。

接口繼承類

首先我們使用extends來實(shí)現(xiàn)接口繼承類。

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();
//別看我只是一只羊,羊兒的聰明難以想象~

在接口繼承類時(shí),可以把類看作一個(gè)接口,但是類中的靜態(tài)方法是不會(huì)繼承過來的。我們?cè)趯?shí)現(xiàn)ISheep接口的變量lanyangyang必須要有類Animalname屬性以及實(shí)現(xiàn)eat方法,并且還要實(shí)現(xiàn)本身的miemie方法。但是我們不必實(shí)現(xiàn)類Animal的靜態(tài)方法run。

是不是覺得還會(huì)有下一個(gè)標(biāo)題類繼承接口,對(duì)不起,這個(gè)真沒有!類繼承接口使用的關(guān)鍵字變成了implements。

extends第二式:三元表達(dá)式條件判斷

extends還有一個(gè)比較常見的用法就是在三元表達(dá)式中進(jìn)行條件判斷,即判斷一個(gè)類型是否可以分配給另一個(gè)類型。這里根據(jù)三元表達(dá)式中是否存在泛型判斷結(jié)果還不一致,首先我們介紹普通的三元表達(dá)式條件判斷。

普通的三元表達(dá)式條件判斷

帶有extends的三元表達(dá)式如下:

type TypeRes=Type1 extends Type2? Type3: Type4;

這里表達(dá)的意思就是如果類型Type1可被分配給類型Type2,則類型TypeResType3,否則取Type4。那怎么理解類型Type1可被分配給類型Type2呢??

我們可以這樣理解:類型為Type1的值可被賦值給類型為Type2的變量??梢跃唧w分為一下幾種情況:

  • Type1Type2為同一種類型。
  • Type1Type2的子類型。
  • Type2類型兼容類型Type1。 接下來我們分情況進(jìn)行驗(yàn)證。

情況一:Type1Type2為同一種類型。

type Type1=string;
type Type2=Type1;
type Type3=true;
type Type4=false;
type TypeRes=Type1 extends Type2? Type3: Type4;
// true

這里Type1Type2為同一種類型。因此Type1可被分配給Type2。因此TypeRes類型最后取為true

情況二:Type1Type2的子類型。

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,即Type1Type2的子類型。因此Type1可被分配給Type2。因此TypeRes類型最后取為true。

情況三: Type2類型兼容類型Type1。

首先還是拋出一個(gè)問題,什么是類型兼容??這個(gè)問題可以從官方文檔中得到答案,大家可以戳類型兼容性詳細(xì)了解!

所謂 Type2類型兼容類型Type1,指得就是Type1類型的值可被賦值給類型為Type2的變量。 舉個(gè)栗子:

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

再舉個(gè)栗子,以函數(shù)的兼容性為例,

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

當(dāng)函數(shù)參數(shù)不同時(shí),看Type2是否兼容Type1,就要看Type1的每個(gè)參數(shù)必須能在Type2里找到對(duì)應(yīng)類型的參數(shù)。 注意的是參數(shù)的名字相同與否無所謂,只看它們的類型。

這里Type1第一個(gè)number類型的參數(shù)是可以在Type2中找到,即Type1類型的函數(shù)可被賦值給類型為Type2的變量。

let fn1:Type1=(a:number)=>{}
let kenny2:Type2=fn1;
// no Error

因此TypeRes類型最后取為true。

帶有泛型的三元表達(dá)式條件判斷

我們先來一個(gè)舉一個(gè)不帶泛型的栗子,大家可以想想結(jié)果是什么。

type Type1=string|number;
type Type2=string;
type Type3=true;
type Type4=false;
type TypeRes=Type1 extends Type2? Type3: Type4;

沒錯(cuò),由于Type1Type2的父類型,因此Type1是不可分配給Type2的,因此TypeRes類型最后取為false

但當(dāng)我們加上泛型之后呢,再來看一個(gè)栗子。

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。這是為什么呢?

原來再使用泛型時(shí),若extends左側(cè)的泛型具體取為一個(gè)聯(lián)合類型時(shí),就會(huì)把聯(lián)合類型中的類型拆開,分別帶入到條件判斷式中進(jìn)行判斷,最后把結(jié)果再進(jìn)行聯(lián)合。上述的栗子中結(jié)果可以這么來看,

(string extends string?true:false)|(number extends string?true:false)
true | false
boolean

在高級(jí)類型中有很多類型實(shí)現(xiàn)便用到了這一特性。

比如Exclude<T, U> -- 從T中剔除可以賦值給U的類型。

type T1 = "a" | "b" | "c" | "d";
type T2 = "a" | "c" | "f"
type ExcludeT1T2=Exclude<T1,T2> //"b"|"d"

該類型的類型實(shí)現(xiàn)為

type Exclude<T, U> = T extends U ? never : T;

當(dāng)T為聯(lián)合類型時(shí),會(huì)自動(dòng)分發(fā)條件,對(duì)T中的所有類型進(jìn)行遍歷,判斷其是否可以分配給類型U,如果是的話便返回never類型,否則返回其原來的類型。最后再將其進(jìn)行聯(lián)合得到一個(gè)結(jié)果聯(lián)合類型。

由于never類型與其他類型聯(lián)合最終得到的還是其他類型,因此便可以從類型T中剔除掉可以賦給U的類型。

那有沒有辦法讓泛型三元表達(dá)式中extends和普通的extends作用相同?有!只需要給泛型加一個(gè)[]。栗子如下:

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第三式:泛型約束

首先我們來回答一下什么是泛型?簡(jiǎn)單來說,泛型就是一種類型變量,普通的變量代表一個(gè)任意的值,而不是一個(gè)特定的值,我們可以把任何值賦給變量,而類型變量代表一個(gè)任意的類型,而不是一個(gè)特定的類型,我們可以把任何類型賦給類型變量。它是一種特殊的變量,只用于表示類型而不是值。

那如果我們不想讓泛型表示任意類型時(shí),該怎么辦?這時(shí)我們就可以使用extends對(duì)泛型進(jìn)行約束,讓泛型表示滿足一定條件的類型。接下來,我們使用extends進(jìn)行泛型的約束。

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}正在奔跑`)};
  }
)
// 懶羊羊正在吃青草蛋糕
//別看我只是一只羊,羊兒的聰明難以想象~

這里我們便對(duì)泛型T進(jìn)行了約束,其必須至少要擁有ISheepname屬性及eat、miemie方法,另外T中若有其他的屬性及方法,則不作限制。這里我們便通過extends對(duì)泛型T進(jìn)行了約束。

其實(shí)泛型約束中的extends也是起到了三元表達(dá)式中類型分配的作用,其中T extends ISheep表示泛型T必須可以分配給類型Isheep。

以上就是TypeScript中extends的正確打開方式詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript extends打開方式的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • JS 里為什么會(huì)有 this

    JS 里為什么會(huì)有 this

    這篇文章主要介紹了JS 里為什么會(huì)有 this,文章主要從語言創(chuàng)造者(JS 之父的角度)來思考 this,我之前那篇講 this 的文章是從使用者的角度寫的,需要的朋友可以參考一下
    2021-10-10
  • Fabric.js 保存自定義屬性方法示例

    Fabric.js 保存自定義屬性方法示例

    這篇文章主要為大家介紹了Fabric.js 保存自定義屬性方法示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-02-02
  • 微信小程序 歡迎界面開發(fā)的實(shí)例詳解

    微信小程序 歡迎界面開發(fā)的實(shí)例詳解

    這篇文章主要介紹了微信小程序 歡迎界面開發(fā)的實(shí)例詳解的相關(guān)資料,這里實(shí)現(xiàn)歡迎界面的簡(jiǎn)單實(shí)例和實(shí)現(xiàn)代碼及實(shí)現(xiàn)效果圖,需要的朋友可以參考下
    2016-11-11
  • 微信小程序 前端源碼邏輯和工作流詳解

    微信小程序 前端源碼邏輯和工作流詳解

    這篇文章主要介紹了微信小程序 前端源碼邏輯和工作流詳解的相關(guān)資料,需要的朋友可以參考下
    2016-10-10
  • 漂亮的仿flash菜單,來自藍(lán)色經(jīng)典

    漂亮的仿flash菜單,來自藍(lán)色經(jīng)典

    漂亮的仿flash菜單,來自藍(lán)色經(jīng)典...
    2006-06-06
  • TypeScript枚舉類型

    TypeScript枚舉類型

    這篇文章主要介紹了TypeScript枚舉類型,所謂的枚舉類型就是為一組數(shù)值賦予名字,下面我們來看看文章是怎么介紹的吧,需要的小伙伴也可以參考一下,希望對(duì)你有所幫助
    2021-12-12
  • 詳解微信小程序如何實(shí)現(xiàn)類似ChatGPT的流式傳輸

    詳解微信小程序如何實(shí)現(xiàn)類似ChatGPT的流式傳輸

    這篇文章主要為大家介紹了微信小程序如何實(shí)現(xiàn)類似ChatGPT的流式傳輸示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2023-03-03
  • Babel?插件開發(fā)&訪問節(jié)點(diǎn)實(shí)例詳解

    Babel?插件開發(fā)&訪問節(jié)點(diǎn)實(shí)例詳解

    這篇文章主要為答案及介紹了Babel?插件開發(fā)&訪問節(jié)點(diǎn)實(shí)例詳解,整理一下?Babel?插件開發(fā)時(shí)用得到的轉(zhuǎn)換操作相關(guān)的?API,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08
  • 微信小程序 form組件詳解及簡(jiǎn)單實(shí)例

    微信小程序 form組件詳解及簡(jiǎn)單實(shí)例

    這篇文章主要介紹了微信小程序 form組件詳解及簡(jiǎn)單實(shí)例的相關(guān)資料,需要的朋友可以參考下
    2017-01-01
  • JavaScript函數(shù)式編程Thunk原理解析

    JavaScript函數(shù)式編程Thunk原理解析

    這篇文章主要為大家介紹了JavaScript函數(shù)式編程Thunk原理示例解析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪
    2022-08-08

最新評(píng)論