国产xxxx99真实实拍_久久不雅视频_高清韩国a级特黄毛片_嗯老师别我我受不了了小说

資訊專欄INFORMATION COLUMN

如何編寫 Typescript 聲明文件

姘擱『 / 3020人閱讀

摘要:函數(shù)重載這個(gè)概念是在一些強(qiáng)類型語(yǔ)言中才有的,依托于,這也算是一門強(qiáng)類型語(yǔ)言了,所以就會(huì)有需要用到這種聲明的地方。

使用TypeScript已經(jīng)有了一段時(shí)間,這的確是一個(gè)好東西,雖說(shuō)在使用的過程中也發(fā)現(xiàn)了一些bug,不過都是些小問題,所以整體體驗(yàn)還是很不錯(cuò)的。

TypeScript之所以叫Type,和它的強(qiáng)類型是分不開的,這也是區(qū)別于JavaScript最關(guān)鍵的一點(diǎn),類型的聲明可以直接寫在代碼中,也可以多帶帶寫一個(gè)用來(lái)表示類型的描述文件*.d.ts。

常用方式

首先在d.ts中是不會(huì)存在有一些簡(jiǎn)單的基本類型定義的(因?yàn)檫@些都是寫在表達(dá)式、變量后邊的,在這里定義沒有任何意義),聲明文件中定義的往往都是一些復(fù)雜結(jié)構(gòu)的類型。

大部分語(yǔ)法都與寫在普通ts文件中的語(yǔ)法一致,也是export后邊跟上要導(dǎo)出的成員。

最簡(jiǎn)單的就是使用type關(guān)鍵字來(lái)定義:

type A = {                 // 定義復(fù)雜結(jié)構(gòu)
  b: number
  c: string
}

type Func = () => number   // 定義函數(shù)

type Key = number | string // 多個(gè)類型
組合類型

以及在TypeScript中有著很輕松的方式針對(duì)type進(jìn)行復(fù)用,比如我們有一個(gè)Animal類型,以及一個(gè)Dog類型,可以使用&來(lái)進(jìn)行復(fù)用。

P.S> &符號(hào)可以拼接多個(gè)

type Animal = {
  weight: number
  height: number
}

type Dog = Animal & {
  leg: number
}
動(dòng)態(tài)的 JSON 類型指定

如果我們有一個(gè)JSON結(jié)構(gòu),而它的key是動(dòng)態(tài)的,那么我們肯定不能將所有的key都寫在代碼中,我們只需要簡(jiǎn)單的指定一個(gè)通配符即可:

type info = {
  [k: string]: string | number // 可以指定多個(gè)類型
}

const infos: info = {
  a: 1,
  b: "2",
  c: true, // error 類型不匹配
}

以及在新的版本中更推薦使用內(nèi)置函數(shù)Record來(lái)實(shí)現(xiàn):

const infos: Record = {
  a: 1,
  b: "2",
  c: true, // error
}
獲取變量的類型

假如我們有一個(gè)JSON對(duì)象,里邊包含了name、age兩個(gè)屬性,我們可以通過一些TypeScript內(nèi)置的工具函數(shù)來(lái)實(shí)現(xiàn)一些有意思的事情。

通過keyoftypeof組合可以得到我們想要的結(jié)果:

const obj = {
  name: "Niko",
  age: 18
}

// 如果是這樣的取值,只能寫在代碼中,不能寫在 d.ts 文件中,因?yàn)槁暶魑募镞叢荒艽嬖趯?shí)際有效的代碼
type keys = keyof typeof obj

let a: keys = "name" // pass
let b: keys = "age"  // pass

let c: keys = "test" // error

而如果我們想要將一個(gè)類型不統(tǒng)一的JSON修改為統(tǒng)一類型的JSON也可以使用這種方式:

const obj = {
  name: "Niko",
  age: 18,
  birthday: new Date()
}

const infos: Record = {
  name: "",
  age: "",
  birthday: 123, // 出錯(cuò),提示類型不匹配
  test: "", // 提示不是`info`的已知類型
}
獲取函數(shù)的返回值類型

又比如說(shuō)我們有一個(gè)函數(shù),函數(shù)會(huì)返回一個(gè)JSON,而我們需要這個(gè)JSON來(lái)作為類型。

那么可以通過ReturnType<>來(lái)實(shí)現(xiàn):

function func () {
  return {
    name: "Niko",
    age: 18
  }
}

type results = ReturnType

// 或者也可以拼接 keyof 獲取所有的 key
type resultKeys = keyof ReturnType

// 亦或者可以放在`Object`中作為動(dòng)態(tài)的`key`存在
type infoJson = Record, string>
在代碼中聲明函數(shù)和class類型

因?yàn)槲覀冎篮瘮?shù)和class在創(chuàng)建的時(shí)候是都有實(shí)際的代碼的(函數(shù)體、構(gòu)造函數(shù))。
但是我們是寫在d.ts聲明文件中的,這只是一個(gè)針對(duì)類型的約束,所以肯定是不會(huì)存在真實(shí)的代碼的,但是如果在普通的ts文件中這么寫會(huì)出錯(cuò)的,所以針對(duì)這類情況,我們需要使用declare關(guān)鍵字,表示我們這里就是用來(lái)定義一個(gè)類型的,而非是一個(gè)對(duì)象、函數(shù):

class Personal {
  name: string
  // ^ 出錯(cuò)了,提示`name`必須顯式的進(jìn)行初始化
}

function getName (personal: Personal): name
// ^ 出錯(cuò)了,提示函數(shù)缺失實(shí)現(xiàn)

以下為正確的使用方式:

-declare class Personal {
+declare class Personal {
  name: string
}

-function getName (personal: Personal): name
+declare function getName (personal: Personal): name

當(dāng)然了,一般情況下是不建議這么定義class的,應(yīng)該使用interface來(lái)代替它,這樣的class應(yīng)該僅存在于針對(duì)非TS模塊的描述,如果是自己開發(fā)的模塊,那么本身結(jié)構(gòu)就具有聲明類型的特性。

函數(shù)重載

這個(gè)概念是在一些強(qiáng)類型語(yǔ)言中才有的,依托于TypeScript,這也算是一門強(qiáng)類型語(yǔ)言了,所以就會(huì)有需要用到這種聲明的地方。

例如我們有一個(gè)add函數(shù),它可以接收string類型的參數(shù)進(jìn)行拼接,也可以接收number類型的參數(shù)進(jìn)行相加。

需要注意的是,只有在做第三方插件的函數(shù)重載定義時(shí)能夠放到d.ts文件中,其他環(huán)境下建議將函數(shù)的定義與實(shí)現(xiàn)放在一起(雖說(shuō)配置paths也能夠?qū)崿F(xiàn)分開處理,但是那樣就失去了對(duì)函數(shù)創(chuàng)建時(shí)的約束)

// index.ts

// 上邊是聲明
function add (arg1: string, arg2: string): string
function add (arg1: number, arg2: number): number
// 因?yàn)槲覀冊(cè)谙逻呌芯唧w函數(shù)的實(shí)現(xiàn),所以這里并不需要添加 declare 關(guān)鍵字

// 下邊是實(shí)現(xiàn)
function add (arg1: string | number, arg2: string | number) {
  // 在實(shí)現(xiàn)上我們要注意嚴(yán)格判斷兩個(gè)參數(shù)的類型是否相等,而不能簡(jiǎn)單的寫一個(gè) arg1 + arg2
  if (typeof arg1 === "string" && typeof arg2 === "string") {
    return arg1 + arg2
  } else if (typeof arg1 === "number" && typeof arg2 === "number") {
    return arg1 + arg2
  }
}

TypeScript 中的函數(shù)重載也只是多個(gè)函數(shù)的聲明,具體的邏輯還需要自己去寫,他并不會(huì)真的將你的多個(gè)重名 function 的函數(shù)體進(jìn)行合并

多個(gè)函數(shù)的順序問題

想象一下,如果我們有一個(gè)函數(shù),傳入Date類型的參數(shù),返回其unix時(shí)間戳,如果傳入Object,則將對(duì)象的具體類型進(jìn)行toString輸出,其余情況則直接返回,這樣的一個(gè)函數(shù)應(yīng)該怎么寫?

僅做示例演示,一般正常人不會(huì)寫出這樣的函數(shù)...

function build (arg: any) {
  if (arg instanceof Date) {
    return arg.valueOf()
  } else if (typeof arg === "object") {
    return Object.prototype.toString.call(arg)
  } else {
    return arg
  }
}

但是這樣的函數(shù)重載在聲明的順序上就很有講究了,一定要將精確性高的放在前邊:

// 這樣是一個(gè)錯(cuò)誤的示例,因?yàn)闊o(wú)論怎樣調(diào)用,返回值都會(huì)是`any`類型
function build(arg: any): any
function build(arg: Object): string
function build(arg: Date): number

因?yàn)?b>TypeScript在查找到一個(gè)函數(shù)重載的聲明以后就會(huì)停止不會(huì)繼續(xù)查找,any是一個(gè)最模糊的范圍,而Object又是包含Date的,所以我們應(yīng)該按照順序從小到大進(jìn)行排列:

function build(arg: Date): number
function build(arg: Object): string
function build(arg: any): any

// 這樣在使用的時(shí)候才能得到正確的類型提示
const res1 = build(new Date()) // number
const res2 = build(() => { })  // string
const res3 = build(true)       // any
一些不需要函數(shù)重載的場(chǎng)景

函數(shù)重載的意義在于能夠讓你知道傳入不同的參數(shù)得到不同的結(jié)果,如果傳入的參數(shù)不同,但是得到的結(jié)果(__類型__)卻相同,那么這里就不要使用函數(shù)重載(沒有意義)。

如果函數(shù)的返回值類型相同,那么就不需要使用函數(shù)重載

function func (a: number): number
function func (a: number, b: number): number

// 像這樣的是參數(shù)個(gè)數(shù)的區(qū)別,我們可以使用可選參數(shù)來(lái)代替函數(shù)重載的定義
function func (a: number, b?: number): number
// 注意第二個(gè)參數(shù)在類型前邊多了一個(gè)`?`

// 亦或是一些參數(shù)類型的區(qū)別導(dǎo)致的
function func (a: number): number
function func (a: string): number

// 這時(shí)我們應(yīng)該使用聯(lián)合類型來(lái)代替函數(shù)重載
function func (a: number | string): number
Interface

interface是在TypeScript中獨(dú)有的,在JavaScript并沒有interface一說(shuō)。
因?yàn)?b>interface只是用來(lái)規(guī)定實(shí)現(xiàn)它的class對(duì)應(yīng)的行為,沒有任何實(shí)質(zhì)的代碼,對(duì)于腳本語(yǔ)言來(lái)說(shuō)這是一個(gè)無(wú)效的操作

在語(yǔ)法上與class并沒有什么太大的區(qū)別,但是在interface中只能夠進(jìn)行成員屬性的聲明,例如function只能夠?qū)懢唧w接收的參數(shù)以及返回值的類型,并不能夠在interface中編寫具體的函數(shù)體,同樣的,針對(duì)成員屬性也不能夠直接在interface中進(jìn)行賦值:

// 這是一個(gè)錯(cuò)誤的示例
interface PersonalIntl {
  name: string = "Niko"

  sayHi (): string {
    return this.name
  }
}

// 在 interface 中只能存在類型聲明
interface PersonalIntl {
  name: string

  sayHi (): string
}

其實(shí)在一些情況下使用interface與普通的type定義也沒有什么區(qū)別。
比如我們要導(dǎo)出一個(gè)存在nameage兩個(gè)屬性的對(duì)象:

// types/personal.d.ts
export interface PersonalIntl {
  name: string
  age:  number
}

// index.d.ts
import { PersonalIntl } from "./types/personal"

const personal: PersonalIntl = {
  name: "Niko",
  age:  18,
}

如果將interface換成type定義也是完全沒問題的:

// types/personal.d.ts
export type PersonalIntl = {
  name: string
  age:  number
}

這樣的定義在基于上邊的使用是完全沒有問題的,但是這樣也僅僅適用于Object字面量的聲明,沒有辦法很好的約束class模式下的使用,所以我們采用interface來(lái)約束class的實(shí)現(xiàn):

import { PersonalIntl } from "./types/personal"

class Personal implements PersonalIntl {
  constructor(public name: string, public age: number) { }

  // 上邊的簡(jiǎn)寫與下述代碼效果一致

  public name: string
  public age: number

  constructor (name: string, age: number) {
    this.name = name
    this.age = age
  }
}

const personal = new Personal("niko", 18)
關(guān)于函數(shù)成員聲明的一些疑惑

首先,在接口中有兩種方式可以定義一個(gè)函數(shù),一個(gè)被定義在實(shí)例上,一個(gè)被定義在原型鏈上。
兩種聲明方式如下:

interface PersonalIntl {
  func1 (): any      // 原型鏈方法

  func2: () => any   // 實(shí)例屬性
}

但是我們?cè)趯?shí)現(xiàn)這兩個(gè)屬性時(shí)其實(shí)是可以互相轉(zhuǎn)換的,并沒有強(qiáng)要求必須使用哪種方式:

class Personal implements PersonalIntl {
  func1 () {
    console.log(this)
  }

  func2 = () => {
    console.log(this)
  }
}

其實(shí)這兩者在編譯后的JavaScript代碼中是有區(qū)別的,并不清楚這是一個(gè)bug還是設(shè)計(jì)就是如此,類似這樣的結(jié)構(gòu):

var Personal = /** @class */ (function () {
    function Personal() {
        var _this = this;
        this.func2 = function () {
            console.log(_this);
        };
    }
    Personal.prototype.func1 = function () {
        console.log(this);
    };
    return Personal;
}());

所以在使用的時(shí)候還是建議最好按照interface定義的方式來(lái)創(chuàng)建,避免一些可能存在的奇奇怪怪的問題。

接口聲明的自動(dòng)合并

因?yàn)?b>interface是TypeScript特有的,所以也會(huì)有一些有意思的特性,比如相同命名的interface會(huì)被自動(dòng)合并:

interface PersonalIntl {
  name: string
}

interface PersonalIntl {
  age: number
}

class Personal implements PersonalIntl {
  name = "Niko"
  age = 18
}
不要在 interface 中使用函數(shù)重載

interface中使用函數(shù)重載,你會(huì)得到一個(gè)錯(cuò)誤的結(jié)果,還是拿上邊的build函數(shù)來(lái)說(shuō),如果在interface中聲明,然后在class中實(shí)現(xiàn),那么無(wú)論怎樣調(diào)用,返回值的類型都會(huì)認(rèn)為是any。

所以正確的做法是在class中聲明重載,在class中實(shí)現(xiàn),interface中最多只定義一個(gè)any,而非三個(gè)重載。

class Util implements UtilIntl {
  build(arg: Date): number
  build(arg: Object): string
  build(arg: any): any

  build(arg: any) {
    if (arg instanceof Date) {
      return arg.valueOf()
    } else if (typeof arg === "object") {
      return Object.prototype.toString.call(arg)
    } else {
      return arg
    }
  }
}
小結(jié)

有關(guān)TypeScript聲明類型聲明相關(guān)的目前就總結(jié)了這些比較常用的,歡迎小伙伴們進(jìn)行補(bǔ)充。

在之前的版本中有存在modulenamespace的定義,但是目前來(lái)看,好像更推薦使用 ES-Modules 版本的 import/export來(lái)實(shí)現(xiàn)類似的功能,而非自定義的語(yǔ)法,所以就略過了這兩個(gè)關(guān)鍵字相關(guān)的描述

官方文檔中有針對(duì)如何編寫聲明文件的模版,可以參考:傳送陣

參考資料

keyof

Record

ReturnType 及其他的內(nèi)置函數(shù)

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://m.specialneedsforspecialkids.com/yun/98380.html

相關(guān)文章

  • Vue2.5+遷移至Typescript指南

    摘要:遷移至指南為什么要遷移至本身是動(dòng)態(tài)弱類型的語(yǔ)言,這樣的特點(diǎn)導(dǎo)致了代碼中充斥著很多的報(bào)錯(cuò),給開發(fā)調(diào)試和線上代碼穩(wěn)定都帶來(lái)了不小的負(fù)面影響??尚行砸?yàn)槭堑某?,不?huì)阻止的運(yùn)行,即使存在類型錯(cuò)誤也不例外,這能讓你的逐步遷移至。 Vue2.5+遷移至Typescript指南 為什么要遷移至Typescript Javascript本身是動(dòng)態(tài)弱類型的語(yǔ)言,這樣的特點(diǎn)導(dǎo)致了Javascript代碼...

    wenshi11019 評(píng)論0 收藏0
  • Vue2.5+遷移至Typescript指南

    摘要:遷移至指南為什么要遷移至本身是動(dòng)態(tài)弱類型的語(yǔ)言,這樣的特點(diǎn)導(dǎo)致了代碼中充斥著很多的報(bào)錯(cuò),給開發(fā)調(diào)試和線上代碼穩(wěn)定都帶來(lái)了不小的負(fù)面影響。可行性因?yàn)槭堑某?,不?huì)阻止的運(yùn)行,即使存在類型錯(cuò)誤也不例外,這能讓你的逐步遷移至。 Vue2.5+遷移至Typescript指南 為什么要遷移至Typescript Javascript本身是動(dòng)態(tài)弱類型的語(yǔ)言,這樣的特點(diǎn)導(dǎo)致了Javascript代...

    Ilikewhite 評(píng)論0 收藏0
  • 使用 TypeScript 編寫一個(gè)完善包含測(cè)試、文檔和持續(xù)集成的庫(kù)

    摘要:?jiǎn)卧獪y(cè)試一個(gè)合格的庫(kù)應(yīng)該包含完整的單元測(cè)試。是的支持版,和是一樣的,它能夠直接運(yùn)行為后綴的單元測(cè)試文件。在目錄下加入然后執(zhí)行即可看到單元測(cè)試結(jié)果。 這篇文章主要是講述如何使用 TypeScript 編寫一個(gè)完善,包含測(cè)試、文檔、持續(xù)集成的庫(kù),涵蓋了編寫整個(gè)庫(kù)所需要的技術(shù)和工具,主要涵蓋: 項(xiàng)目目錄骨架 TypeScript 配置 使用 jest 單元測(cè)試 使用 vuepress 編寫...

    lingdududu 評(píng)論0 收藏0
  • 一篇文章學(xué)會(huì) TypeScript

    摘要:接下來(lái)來(lái)看一段代碼示例語(yǔ)法與語(yǔ)言比較當(dāng)類型不對(duì)的時(shí)候,會(huì)提示錯(cuò)誤編譯后語(yǔ)法聯(lián)想大致可以把它看成是加了類型系統(tǒng)的。 一篇文章學(xué)會(huì) TypeScript (內(nèi)部分享標(biāo)題:TypeScript 基礎(chǔ)) 這篇文章是我在公司前端小組內(nèi)部的演講分享稿,目的是教會(huì)大家使用 TypeScript,這篇文章雖然標(biāo)著基礎(chǔ),但我指的基礎(chǔ)是學(xué)完后就能夠勝任 TypeScript 的開發(fā)工作。從我分享完的效果來(lái)...

    itvincent 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<