最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

使用TypeScript在接口中定義靜態(tài)方法詳解

 更新時(shí)間:2023年10月31日 11:38:38   作者:it鍵盤俠  
當(dāng)我們談?wù)撁嫦驅(qū)ο缶幊虝r(shí),最難理解的事情之一就是靜態(tài)屬性與實(shí)例屬性的概念,尤其是當(dāng)我們?cè)噲D在靜態(tài)類型的基礎(chǔ)上進(jìn)行動(dòng)態(tài)語(yǔ)言類型化時(shí),在本文中,我將主要介紹一下如何使用TypeScript在接口中定義靜態(tài)方法,需要的朋友可以參考下

靜態(tài)方法

靜態(tài)方法或靜態(tài)屬性是存在于類的任何實(shí)例中的屬性,它們是在構(gòu)造函數(shù)級(jí)別定義的,也就是說(shuō),類本身具有這些方法,因此這些類的所有實(shí)例也將具有這些方法。

例如,當(dāng)我們創(chuàng)建一個(gè)域?qū)ο蠡驍?shù)據(jù)庫(kù)實(shí)體時(shí),就會(huì)用到常見(jiàn)的靜態(tài)方法:

class Person {
  static fromObject (obj: Record<string, unknown>) {
    const instance = new Person()
    instance.prop = obj.prop
    return instance
  }

  toObject () {
    return {
     prop: this.prop
    }
}

fromObject 方法存在于所有類中,它位于任何實(shí)例之上,因此不能使用 this 關(guān)鍵字,因?yàn)?this 尚未初始化,而且你所處的上下文高于 this 可以引用的任何實(shí)例。

在本例中,我們接收了一個(gè)對(duì)象,并直接用它創(chuàng)建了一個(gè)新的類實(shí)例。要執(zhí)行這段代碼,請(qǐng)不要執(zhí)行類似以下的標(biāo)準(zhǔn)操作

const p = new Person()
p.fromObject(etc) // error, the property does not exist in the instance

我們需要直接從類的構(gòu)造函數(shù)中調(diào)用該方法:

const p = Person.fromObject(etc)

引出的問(wèn)題

靜態(tài)方法在強(qiáng)類型語(yǔ)言中非常常見(jiàn),因?yàn)轭惖撵o態(tài)時(shí)刻和 "動(dòng)態(tài) "時(shí)刻之間有明確的區(qū)分。

但是,當(dāng)我們需要使用靜態(tài)類型對(duì)動(dòng)態(tài)語(yǔ)言進(jìn)行類型化時(shí),會(huì)發(fā)生什么情況呢?

在 TypeScript 中,當(dāng)我們嘗試聲明一個(gè)類有動(dòng)態(tài)方法和靜態(tài)方法,并嘗試在接口中描述這兩種方法時(shí),就會(huì)出現(xiàn)一些錯(cuò)誤:

interface Serializable {
  fromObject (obj: Record<string, unknown>): Person
  toObject (): Record<string, unknown>
}

class Person implements Serializable
// Class 'Person' incorrectly implements interface 'Serializable'.
// Property 'fromObject' is missing in type 'Person' but required in type
// 'Serializable'.

出現(xiàn)這種情況的原因是,TypeScript 中的接口作用于類的 dynamic side(動(dòng)態(tài)端),因此就好像所有接口都是相關(guān)類的實(shí)例,而不是類本身。

幸運(yùn)的是,TypeScript 提供了一種將類聲明為構(gòu)造函數(shù)的方法,即所謂的構(gòu)造函數(shù)簽名(Constructor Signatures):

interface Serializable {
  new (...args: any[]): any
  fromObject(obj: Record<string, unknown>): Person
  toObject(): Record<string, unknown>
}

現(xiàn)在應(yīng)該能用了吧?遺憾的是,即使你手動(dòng)實(shí)現(xiàn)了該方法,該類仍然會(huì)說(shuō)你沒(méi)有實(shí)現(xiàn) fromObject 方法。

靜態(tài)反射問(wèn)題

例如,如果我們想創(chuàng)建一個(gè)數(shù)據(jù)庫(kù)類,直接使用類中的實(shí)體名稱來(lái)創(chuàng)建文件,這可以通過(guò)任何類中的 name 屬性來(lái)實(shí)現(xiàn),這是一個(gè)靜態(tài)屬性,存在于所有可實(shí)例化的對(duì)象中:

interface Serializable {
  toObject(): any
}

class DB {
  constructor(entity: Serializable) {
    const path = entity.name // name does not exist in the property
  }
}

好了,我們可以將 entity.name 替換為 entity.constructor.name,這也行得通,但當(dāng)我們需要從一個(gè)對(duì)象創(chuàng)建一個(gè)新實(shí)體時(shí)怎么辦呢?

interface Serializable {
  toObject(): any
}

class DB {
  #entity: Serializable
  constructor(entity: Serializable) {
    const path = entity.constructor.name
    this.#entity = entity
  }

  readFromFile() {
    // we read from this file here
    const object = 'file content as an object'
    return this.#entity.fromObject(object) // fromObject does not exist
  }
}

因此,我們有一個(gè)選擇:要么優(yōu)先處理實(shí)例,要么優(yōu)先處理構(gòu)造函數(shù)...

解決方案

幸運(yùn)的是,我們有辦法解決這個(gè)問(wèn)題。我們定義接口的兩部分,即靜態(tài)部分和實(shí)例部分:

export interface SerializableStatic {
  new (...args: any[]): any
  fromObject(data: Record<string, unknown>): InstanceType<this>
}

export interface Serializable {
  id: string
  toJSON(): string
}

需要注意的是,in 中的構(gòu)造函數(shù)的類型new(...args: any[]): any 必須與 return 中的類型相同any,否則就會(huì)成為循環(huán)引用

有了類的這兩部分類型,我們可以說(shuō)類只實(shí)現(xiàn)了實(shí)例部分:

class Person implements Serializable {
  // ...
}

現(xiàn)在,我們可以說(shuō)我們的數(shù)據(jù)庫(kù)將接收兩種類型的參數(shù),一種是靜態(tài)部分,我們稱之為 S,另一個(gè)是動(dòng)態(tài)(或?qū)嵗┎糠?,我們稱之為 I,S 將始終擴(kuò)展 SerializableStatic而 I 將始終擴(kuò)展 Serializable,默認(rèn)情況下,它將是 S 的實(shí)例類型,可以通過(guò) InstanceType<S>類型使用程序來(lái)定義:

    
class Database<S extends SerializableStatic, I extends Serializable = InstanceType<S>> {}
    

例如,現(xiàn)在我們可以正常使用我們的屬性:

class Database<S extends SerializableStatic, I extends Serializable = InstanceType<S>> {
  #dbPath: string
  #data: Map<string, I> = new Map()
  #entity: S

  constructor(entity: S) {
    this.#dbPath = resolve(dirname(import.meta.url), `.data/${entity.name.toLowerCase()}.json`)
    this.#entity = entity
    this.#initialize()
  }
}

在 #initialize 方法中,我們將使用 fromObject 方法直接讀取文件,并將其轉(zhuǎn)化為一個(gè)類的實(shí)例:

class Database<S extends SerializableStatic, I extends Serializable = InstanceType<S>> {
  #dbPath: string
  #data: Map<string, I> = new Map()
  #entity: S

  constructor(entity: S) {
    this.#dbPath = resolve(dirname(import.meta.url), `.data/${entity.name.toLowerCase()}.json`)
    this.#entity = entity
    this.#initialize()
  }

  #initialize() {
    if (existsSync(this.#dbPath)) {
      const data: [string, Record<string, unknown>][] = JSON.parse(readFileSync(this.#dbPath, 'utf-8'))
      for (const [key, value] of data) {
        this.#data.set(key, this.#entity.fromObject(value))
      }
      return
    }
    this.#updateFile()
  }
}

此外,我們還可以使用 get 和 getAll 等方法,甚至是只接收和返回實(shí)例的保存方法。

get(id: string): I | undefined {
  return this.#data.get(id)
}

getAll(): I[] {
  return [...this.#data.values()]
}

save(entity: I): this {
  this.#data.set(entity.id, entity)
  return this.#updateFile()
}

現(xiàn)在,當(dāng)我們使用這種類型的數(shù)據(jù)庫(kù)時(shí),例如

class Person implements Serializable {
  // enter code here
}

const db = new DB(Person)
const all = db.getAll() // Person[]
const oneOrNone = db.get(1) // Person | undefined
db.save(new Person()) // DB<Person>

以上就是使用TypeScript在接口中定義靜態(tài)方法詳解的詳細(xì)內(nèi)容,更多關(guān)于TypeScript定義靜態(tài)方法的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • js中new一個(gè)對(duì)象的過(guò)程

    js中new一個(gè)對(duì)象的過(guò)程

    本文主要介紹了js中new一個(gè)對(duì)象的過(guò)程。具有很好的參考價(jià)值,下面跟著小編一起來(lái)看下吧
    2017-02-02
  • JavaScript中處理數(shù)組、對(duì)象等特殊類型的操作匯總

    JavaScript中處理數(shù)組、對(duì)象等特殊類型的操作匯總

    JavaScript 提供了豐富的內(nèi)置方法和技巧來(lái)處理數(shù)組,對(duì)象及其他特殊類型,以下是一些常見(jiàn)的操作匯總,希望對(duì)大家有一定的幫助
    2025-10-10
  • 前端實(shí)現(xiàn)瀏覽器自定義滾動(dòng)條寫法實(shí)例

    前端實(shí)現(xiàn)瀏覽器自定義滾動(dòng)條寫法實(shí)例

    自定義滾動(dòng)條最早是IE玩出來(lái)的,但是后來(lái),不知道為什么IE把這個(gè)有意思的功能廢棄了,下面這篇文章主要給大家介紹了關(guān)于前端實(shí)現(xiàn)瀏覽器自定義滾動(dòng)條寫法的相關(guān)資料,文中通過(guò)代碼介紹的非常詳細(xì),需要的朋友可以參考下
    2024-06-06
  • JavaScript中最容易混淆的作用域、提升、閉包知識(shí)詳解(推薦)

    JavaScript中最容易混淆的作用域、提升、閉包知識(shí)詳解(推薦)

    在web前端開(kāi)發(fā)中js中的作用域,提升,閉包知識(shí)是經(jīng)常用到的也是很容易混淆的知識(shí)點(diǎn),接下來(lái)小編整理了本教程幫助大家學(xué)習(xí)
    2016-09-09
  • 微信小程序聊天功能的示例代碼

    微信小程序聊天功能的示例代碼

    這篇文章主要介紹了微信小程序聊天功能的示例代碼,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-01-01
  • js實(shí)現(xiàn)點(diǎn)擊圖片自動(dòng)提交action的簡(jiǎn)單方法

    js實(shí)現(xiàn)點(diǎn)擊圖片自動(dòng)提交action的簡(jiǎn)單方法

    下面小編就為大家?guī)?lái)一篇js實(shí)現(xiàn)點(diǎn)擊圖片自動(dòng)提交action的簡(jiǎn)單方法。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧
    2016-10-10
  • node.js Web應(yīng)用框架Express入門指南

    node.js Web應(yīng)用框架Express入門指南

    這篇文章主要介紹了node.js Web應(yīng)用框架Express入門指南,從安裝到各種技術(shù)的應(yīng)用,都進(jìn)行了講解,是一篇不錯(cuò)的Express入門教程,需要的朋友可以參考下
    2014-05-05
  • js實(shí)現(xiàn)的倒計(jì)時(shí)按鈕實(shí)例

    js實(shí)現(xiàn)的倒計(jì)時(shí)按鈕實(shí)例

    這篇文章主要介紹了js實(shí)現(xiàn)的倒計(jì)時(shí)按鈕,實(shí)例分析了javascript倒計(jì)時(shí)效果的相關(guān)實(shí)現(xiàn)技巧,需要的朋友可以參考下
    2015-06-06
  • JavaScript中的DOM和Timer的基本操作

    JavaScript中的DOM和Timer的基本操作

    掌握J(rèn)avaScript中的DOM操作可通過(guò)id、class、標(biāo)簽名及CSS選擇器進(jìn)行元素選擇和內(nèi)容修改,Timer定時(shí)器功能包括設(shè)置延時(shí)和間隔執(zhí)行,詳細(xì)介紹了事件處理器和事件監(jiān)聽(tīng)函數(shù)的使用,以及避免事件覆蓋的建議
    2024-10-10
  • uniapp實(shí)現(xiàn)滑動(dòng)評(píng)分效果

    uniapp實(shí)現(xiàn)滑動(dòng)評(píng)分效果

    這篇文章主要為大家詳細(xì)介紹了uniapp實(shí)現(xiàn)滑動(dòng)評(píng)分效果,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-09-09

最新評(píng)論

康保县| 潼关县| 廊坊市| 邢台县| 北京市| 手机| 定西市| 手机| 长兴县| 文水县| 郧西县| 柞水县| 黎城县| 赤水市| 宜良县| 潼关县| 军事| 若羌县| 荆门市| 河源市| 巨鹿县| 南宫市| 西宁市| 土默特右旗| 中山市| 宁陵县| 凭祥市| 旬阳县| 阜城县| 长白| 永济市| 清流县| 泰州市| 临邑县| 东山县| 顺昌县| 马边| 宁南县| 鄂尔多斯市| 葫芦岛市| 微博|