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

TypeScript接口與泛型全面精講

 更新時間:2022年10月22日 11:27:59   作者:YinJie…  
接口是一系列抽象方法的聲明,是一些方法特征的集合,這些方法都應(yīng)該是抽象的,需要由具體的類去實現(xiàn),然后第三方就可以通過這組抽象方法調(diào)用,讓具體的類執(zhí)行具體的方法,泛型是靜態(tài)類型語言的基本特征,允許將類型作為參數(shù)傳遞給另一個類型、函數(shù)、或者其他結(jié)構(gòu)

一、接口

1. Interface 接口類型

(1) 接口類型的基本使用

如下定義一個接口類型:

/ ** 關(guān)鍵字 接口名稱 */
interface ProgramLanguage {
  /** 語言名稱 */
  name: string;
  /** 使用年限 */
  age: () => number;
}

現(xiàn)在我們就可以直接使用 ProgramLanguage 接口來定義參數(shù)的類型了:

function NewStudy(language: ProgramLanguage) {
  console.log(`ProgramLanguage ${language.name} created ${language.age()} years ago.`);
}

我們還可以通過復(fù)用接口類型定義來約束其他邏輯。比如,我們通過如下所示代碼定義了一個類型為 ProgramLanguage 的變量 TypeScript :

let TypeScript: ProgramLanguage;

(2) 可缺省屬性

/** 關(guān)鍵字 接口名稱 */
interface OptionalProgramLanguage {
  /** 語言名稱 */
  name: string;
  /** 使用年限 */
  age?: () => number;
}
let OptionalTypeScript: OptionalProgramLanguage = {
  name: 'TypeScript'
}; // ok

當屬性被標注為可缺省后,它的類型就變成了顯式指定的類型與 undefined 類型組成的聯(lián)合類型,比如示例中 OptionalTypeScript 的 age 屬性類型就變成了如下所示內(nèi)容:

(() => number) | undefined;

(3) 只讀屬性

interface ReadOnlyProgramLanguage {
  /** 語言名稱 */
  readonly name: string;
  /** 使用年限 */
  readonly age: (() => number) | undefined;
}
let ReadOnlyTypeScript: ReadOnlyProgramLanguage = {
name: 'TypeScript',
age: undefined
}
/** ts(2540)錯誤,name 只讀 */
ReadOnlyTypeScript.name = 'JavaScript';

(4) 定義函數(shù)類型

在以上示例中,你可能會覺得接口類型僅能用來定義對象的類型,但是接口類型還可以用來定義函數(shù)的類型(僅僅是定義函數(shù)的類型,而不包含函數(shù)的實現(xiàn)),具體示例如下:

interface person {
    name: 'zyj',
    age: 20
}
interface func {
    (persona: person): void
}
let printmessage: func = persona => { console.log(`我是${persona.name},我的年齡是${persona.age}歲`)}

我們定義了一個接口類型 func,它有一個函數(shù)類型的匿名成員,函數(shù)參數(shù)類型 person,返回值的類型是 void,通過這樣的格式定義的接口類型又被稱之為可執(zhí)行類型,也就是一個函數(shù)類型。

然后我們聲明了一個 func 類型的變量,并賦給它一個箭頭函數(shù)作為值。根據(jù)上下文類型推斷,賦值操作左側(cè)的 func 類型是可以約束箭頭函數(shù)的類型,所以即便我們沒有顯式指定函數(shù)參數(shù) persona 的類型,TypeScript 也能推斷出它的類型就是 person。

實際上,我們很少使用接口類型來定義函數(shù)的類型,更多使用內(nèi)聯(lián)類型或類型別名配合箭頭函數(shù)語法來定義函數(shù)類型,具體示例如下:

type personType = (persona: person) => void

我們給箭頭函數(shù)類型指定了一個別名 personType,在其他地方就可以直接復(fù)用 personType,而不用重新聲明新的箭頭函數(shù)類型定義。

(5) 索引簽名

索引名稱的類型分為 string 和 number 兩種,通過如下定義的 LanguageRankInterface 和 LanguageYearInterface 兩個接口,我們可以用來描述索引是任意數(shù)字或任意字符串的對象:

interface LanguageRankInterface {
  [rank: number]: string;
}
interface LanguageYearInterface {
  [name: string]: number;
}
{
  let LanguageRankMap: LanguageRankInterface = {
    1: 'TypeScript', // ok
    2: 'JavaScript', // ok
    'WrongINdex': '2012' // ts(2322) 不存在的屬性名
  };
  let LanguageMap: LanguageYearInterface = {
        TypeScript: 2012, // ok
        JavaScript: 1995, // ok
        1: 1970 // ok
  };
}

注意:在上述示例中,數(shù)字作為對象索引時,它的類型既可以與數(shù)字兼容,也可以與字符串兼容,這與 JavaScript 的行為一致。因此,使用 0 或 '0' 索引對象時,這兩者等價。

注意:雖然屬性可以與索引簽名進行混用,但是屬性的類型必須是對應(yīng)的數(shù)字索引或字符串索引的類型的子集,否則會出現(xiàn)錯誤提示。

{
  interface StringMap {
    [prop: string]: number;
    age: number; // ok
    name: string; // ts(2411) name 屬性的 string 類型不能賦值給字符串索引類型 number
  }
  interface NumberMap {
    [rank: number]: string;
    1: string; // ok
    0: number; // ts(2412) 0 屬性的 number 類型不能賦值給數(shù)字索引類型 string
  }
  interface LanguageRankInterface {
    name: string; // ok
    0: number; // ok
    [rank: number]: string;
    [name: string]: number;
  }
}

在上述示例中,因為接口 StringMap 屬性 name 的類型 string 不是它所對應(yīng)的字符串索引(第 3 行定義的 prop: string)類型 number 的子集,所以會提示一個錯誤。同理,因為接口 NumberMap 屬性 0 的類型 number 不是它所對應(yīng)的數(shù)字索引(第 8 行定義的 rank: number)類型 string 的子集,所以也會提示一個錯誤。

2. Type 類型別名

接口類型的一個作用是將內(nèi)聯(lián)類型抽離出來,從而實現(xiàn)類型可復(fù)用。其實,我們也可以使用類型別名接收抽離出來的內(nèi)聯(lián)類型實現(xiàn)復(fù)用。

/** 類型別名 */
{
  type LanguageType = {
    /** 以下是接口屬性 */
    /** 語言名稱 */
    name: string;
    /** 使用年限 */
    age: () => number;
  }
}

針對接口類型無法覆蓋的場景,比如組合類型、交叉類型,我們只能使用類型別名來接收,如下代碼所示:

{
  /** 聯(lián)合 */
  type MixedType = string | number;
  /** 交叉 */
  type IntersectionType = { id: number; name: string; } 
    & { age: number; name: string };
  /** 提取接口屬性類型 */
  type AgeType = ProgramLanguage['age'];  
}

注意:類型別名,誠如其名,即我們僅僅是給類型取了一個新的名字,并不是創(chuàng)建了一個新的類型。

3. one question

如何定義如下所示 age 屬性是數(shù)字類型,而其他不確定的屬性是字符串類型的數(shù)據(jù)結(jié)構(gòu)的對象?

{
  age: 1, // 數(shù)字類型
  anyProperty: 'str', // 其他不確定的屬性都是字符串類型
  ...
}

我們肯定要用到兩個接口的聯(lián)合類型及類型縮減,這個問題的核心在于找到一個既是 number 的子類型,這樣 age 類型縮減之后的類型就是 number;同時也是 string 的子類型,這樣才能滿足屬性和 string 索引類型的約束關(guān)系。哪個類型滿足這個條件呢?那只有特殊類型 never。

never 有一個特性是它是所有類型的子類型,自然也是 number 和 string 的子類型,所以答案如下代碼所示:

  type UnionInterce =
  | {
      age: number;
    }
  | ({
      age: never;
      [key: string]: string;
    });
  const O: UnionInterce = {
    age: 2,
    string: 'string'
  };

在上述代碼中,我們在第 3 行定義了 number 類型的 age 屬性,第 6 行定義了 never 類型的 age 屬性,等價于 age 屬性的類型是由 number 和 never 類型組成的聯(lián)合類型,所以我們可以把 number 類型的值(比如說數(shù)字字面量 1)賦予 age 屬性;但是不能把其他任何類型的值(比如說字符串字面量 'string' )賦予 age。

同時,我們在第 5 行~第 8 行定義的接口類型中,還額外定義了 string 類型的字符串索引簽名。因為 never 同時又是 string 類型的子類型,所以 age 屬性的類型和字符串索引簽名類型不沖突。如第 9 行~第 12 行所示,我們可以把一個 age 屬性是 2、string 屬性是 'string' 的對象字面量賦值給 UnionInterce 類型的變量 O。

二、泛型

1. 泛型類型參數(shù)

function reflect<P>(param: P) {
  return param;
}

這里我們可以看到,尖括號中的 P 表示泛型參數(shù)的定義,param 后的 P 表示參數(shù)的類型是泛型 P(即類型受 P 約束)。

const reflectStr = reflect<string>('string'); // str 類型是 string
const reflectNum = reflect<number>(1); // num 類型 number

然后在調(diào)用函數(shù)時,我們也通過 <> 語法指定了如下所示的 string、number 類型入?yún)?,相?yīng)地,reflectStr 的類型是 string,reflectNum 的類型是 number。

另外,如果調(diào)用泛型函數(shù)時受泛型約束的參數(shù)有傳值,泛型參數(shù)的入?yún)⒖梢詮膮?shù)的類型中進行推斷,而無須再顯式指定類型(可缺?。虼松线叺氖纠梢院唽憺槿缦率纠?/p>

const reflectStr2 = reflect('string'); // str 類型是 string
const reflectNum2 = reflect(1); // num 類型 number

泛型不僅可以約束函數(shù)整個參數(shù)的類型,還可以約束參數(shù)屬性、成員的類型,比如參數(shù)的類型可以是數(shù)組、對象,如下示例:

function reflectArray<P>(param: P[]) {
  return param;
}
const reflectArr = reflectArray([1, '1']); // reflectArr 是 (string | number)[]

這里我們約束了 param 的類型是數(shù)組,數(shù)組的元素類型是泛型入?yún)ⅰ?/p>

2. 泛型類

在類的定義中,我們還可以使用泛型用來約束構(gòu)造函數(shù)、屬性、方法的類型,如下代碼所示:

class Memory<S> {
  store: S;
  constructor(store: S) {
    this.store = store;
  }
  set(store: S) {
    this.store = store;
  }
  get() {
    return this.store;
  }
}
const numMemory = new Memory<number>(1); // <number> 可缺省
const getNumMemory = numMemory.get(); // 類型是 number
numMemory.set(2); // 只能寫入 number 類型
const strMemory = new Memory(''); // 缺省 <string>
const getStrMemory = strMemory.get(); // 類型是 string
strMemory.set('string'); // 只能寫入 string 類型

3. 泛型類型

將類型入?yún)⒌亩x移動到類型別名或接口名稱后,此時定義的一個接收具體類型入?yún)⒑蠓祷匾粋€新類型的類型就是泛型類型。

type GenericReflectFunction<P> = (param: P) => P;
interface IGenericReflectFunction<P> {
  (param: P): P;
}
const reflectFn4: GenericReflectFunction<string> = reflect; // 具象化泛型
const reflectFn5: IGenericReflectFunction<number> = reflect; // 具象化泛型
const reflectFn3Return = reflectFn4('string'); // 入?yún)⒑头祷刂刀急仨毷?string 類型
const reflectFn4Return = reflectFn5(1); //  入?yún)⒑头祷刂刀急仨毷?number 類型

在泛型定義中,我們甚至可以使用一些類型操作符進行運算表達,使得泛型可以根據(jù)入?yún)⒌念愋脱苌龈鳟惖念愋?,如下代碼所示:

type StringOrNumberArray<E> = E extends string | number ? E[] : E;
type StringArray = StringOrNumberArray<string>; // 類型是 string[]
type NumberArray = StringOrNumberArray<number>; // 類型是 number[]
type NeverGot = StringOrNumberArray<boolean>; // 類型是 boolean

發(fā)散一下,如果我們給上面這個泛型傳入了一個 string | boolean 聯(lián)合類型作為入?yún)?,將會得到什么類型呢?且看如下所示示例?/p>

type BooleanOrString = string | boolean;
type WhatIsThis = StringOrNumberArray<BooleanOrString>; // 好像應(yīng)該是 string | boolean ?
type BooleanOrStringGot = BooleanOrString extends string | number ? BooleanOrString[] : BooleanOrString; //  string | boolean

如果你使用 VS Code 嘗試了這個示例,并 hover 類型別名 WhatIsThis ,那么你會發(fā)現(xiàn)顯示的類型將是 boolean | string[]。這個就是所謂的分配條件類型:

在條件類型判斷的情況下(比如上邊示例中出現(xiàn)的 extends),如果入?yún)⑹锹?lián)合類型,則會被拆解成一個個獨立的(原子)類型(成員)進行類型運算。

比如上邊示例中的 string | boolean 入?yún)ⅲ缺徊鸾獬?string 和 boolean 這兩個獨立類型,再分別判斷是否是 string | number 類型的子集。因為 string 是子集而 boolean 不是,所以最終我們得到的 WhatIsThis 的類型是 boolean | string[]。

4. 泛型約束

function reflectSpecified<P extends number | string | boolean>(param: P):P {
  return param;
}
reflectSpecified('string'); // ok
reflectSpecified(1); // ok
reflectSpecified(true); // ok
reflectSpecified(null); // ts(2345) 'null' 不能賦予類型 'number | string | boolean'

同樣,我們也可以把接口泛型入?yún)⒓s束在特定的范圍內(nèi),如下代碼所示:

interface ReduxModelSpecified<State extends { id: number; name: string }> {
  state: State
}
type ComputedReduxModel1 = ReduxModelSpecified<{ id: number; name: string; }>; // ok
type ComputedReduxModel2 = ReduxModelSpecified<{ id: number; name: string; age: number; }>; // ok
type ComputedReduxModel3 = ReduxModelSpecified<{ id: string; name: number; }>; // ts(2344)
type ComputedReduxModel4 = ReduxModelSpecified<{ id: number;}>; // ts(2344)

在上述示例中,ReduxModelSpecified 泛型僅接收 { id: number; name: string } 接口類型的子類型作為入?yún)ⅰ?/p>

到此這篇關(guān)于TypeScript接口與泛型全面精講的文章就介紹到這了,更多相關(guān)TypeScript接口與泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • 自制簡易打賞功能的實例

    自制簡易打賞功能的實例

    下面小編就為大家?guī)硪黄灾坪喴状蛸p功能的實例。小編覺得挺不錯的,現(xiàn)在就分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-09-09
  • 解析JSON字符串報錯syntaxError:unexpected?end?of?JsoN?input如何解決

    解析JSON字符串報錯syntaxError:unexpected?end?of?JsoN?input如何解決

    這篇文章主要給大家介紹了關(guān)于解析JSON字符串報錯syntaxError:unexpected?end?of?JsoN?input如何解決的相關(guān)資料,文中通過代碼將解決的辦法介紹的非常詳細,需要的朋友可以參考下
    2024-05-05
  • echarts整合多個類似option的方法實例

    echarts整合多個類似option的方法實例

    這篇文章主要給大家介紹了關(guān)于echarts整合多個類似option的相關(guān)資料,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2018-07-07
  • D3.js入門之D3?DataJoin的使用

    D3.js入門之D3?DataJoin的使用

    DataJoin(數(shù)據(jù)連接)是D3中很重要的一個概念。D3是基于數(shù)據(jù)操作DOM的js庫,DataJoin使我們能夠根據(jù)現(xiàn)有?HTML?文檔中的數(shù)據(jù)集注入、修改和刪除元素。本文主要和大家詳細聊聊DataJoin的使用,感興趣的可以學習一下
    2022-11-11
  • 如何自定義刪除無依賴文件的webpack插件

    如何自定義刪除無依賴文件的webpack插件

    通過自定義webpack插件,利用執(zhí)行完成編譯的封存階段后,產(chǎn)生的產(chǎn)物module.fileDependencies,生成依賴的文件組,通過讀文件的方式,將待掃描的文件組和有依賴關(guān)系的文件進行對比,這篇文章主要介紹了自定義刪除無依賴文件的webpack插件,需要的朋友可以參考下
    2023-12-12
  • 微信小程序?qū)崿F(xiàn)車牌鍵盤

    微信小程序?qū)崿F(xiàn)車牌鍵盤

    這篇文章主要為大家詳細介紹了微信小程序?qū)崿F(xiàn)車牌鍵盤,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2022-07-07
  • 小程序如何在不同設(shè)備上自適應(yīng)生成海報的實現(xiàn)方法

    小程序如何在不同設(shè)備上自適應(yīng)生成海報的實現(xiàn)方法

    這篇文章主要介紹了小程序如何在不同設(shè)備上自適應(yīng)生成海報的實現(xiàn)方法,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友們下面隨著小編來一起學習學習吧
    2019-08-08
  • javascript實現(xiàn)密碼驗證

    javascript實現(xiàn)密碼驗證

    這篇文章主要介紹了javascript密碼驗證的實現(xiàn)方法,過程很簡單具有一定的參考價值,適合初學者學習研究,感興趣的小伙伴們可以參考一下
    2015-11-11
  • javascript?Redux的狀態(tài)管理詳解

    javascript?Redux的狀態(tài)管理詳解

    這篇文章主要為大家詳細介紹了javascript?Redux的狀態(tài)管理,文中示例代碼介紹的非常詳細,具有一定的參考價值,感興趣的小伙伴們可以參考一下,希望能夠給你帶來幫助
    2022-02-02
  • JavaScript中btoa和atob全局函數(shù)示例詳解

    JavaScript中btoa和atob全局函數(shù)示例詳解

    這篇文章主要給大家介紹了關(guān)于JavaScript中btoa和atob全局函數(shù)的相關(guān)資料,atob和btoa是window對象的兩個函數(shù),用來編碼解碼Base64,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-08-08

最新評論