如何編寫一個d.ts文件

這篇文章主要講怎麼寫一個typescript的描述文件(以d.ts結尾的文件名,好比xxx.d.ts)。

總結一下:
從類型type角度分爲:基本類型(string、number、boolean等)及其混合;複雜類型(class、function、object)及其混合(好比說又是class又是function)。
從代碼有效範圍分爲:全局變量、模塊變量和又是全局變量又是模塊變量的。
從定義文件來講:本身寫的.d.ts文件和擴展別人寫的.d.ts文件。
以上三個角度,應該覆蓋了描述文件的各個方面了。javascript

2019.09.12更新說明:html

1.增長了用interface的方式聲明函數。
2.增長了在使用模塊化導入的狀況下如何聲明全局變量。

2018.12.18更新說明:java

1.增長了全局聲明的原理說明。
2.增長了es6的import、export對應的d.ts文件寫法。
3.增長了d.ts文件放置位置的說明。

發現了一個關於typescript比較好的入門教程:https://ts.xcatliu.com/basics...,這是其中的關於描述文件的文檔。jquery

最近開始從js轉ts了。可是要用到一些描述文件(d.ts),經常使用的好比jquery等均可以經過 npm下載到別人已經寫好的npm install @types/jquery。可是仍是有一些小衆的或者公司內部的公共庫或者之前寫過的公用js代碼須要本身手動寫描述文件。es6

以前也從網上面也找了一些資料,但仍是看的雲裏霧裏模糊不清,通過一段摸索,將摸索的結果記錄下來,也但願能夠給別人一個參考。ajax

若是你只寫js,d.ts對你來講也是有用的,大部分編輯器能識別d.ts文件,當你寫js代碼的時候給你智能提示。效果像這樣:typescript

clipboard.png

詳情能夠看我之前寫過的一些文章:https://segmentfault.com/a/11...express

一般,咱們寫js的是時候有兩種引入js的方式:
1,在html文件中經過<script>標籤全局引入全局變量。
2,經過模塊加載器require其餘js文件:好比這樣var j=require('jquery')npm

全局類型

首先以第一種方式舉例。json

變量

好比如今有一個全局變量,那對應的d.ts文件裏面這樣寫。

declare var aaa:number

其中關鍵字declare表示聲明的意思。在d.ts文件裏面,在最外層聲明變量或者函數或者類要在前面加上這個關鍵字。在typescript的規則裏面,若是一個.ts.d.ts文件若是沒有用到import或者export語法的話,那麼最頂層聲明的變量就是全局變量。

因此咱們在這裏聲明瞭一個全局變量aaa,類型是數字類型(number)。固然了也能夠是string類型或者其餘或者:

declare var aaa:number|string //注意這裏用的是一個豎線表示"或"的意思

若是是常量的話用關鍵字const表示:

declare const max:200

函數

由上面的全局變量的寫法咱們很天然的推斷出一個全局函數的寫法以下:

/** id是用戶的id,能夠是number或者string */
decalre function getName(id:number|string):string

最後的那個string表示的是函數的返回值的類型。若是函數沒有返回值能夠用void表示。
在js裏面調用的時候就會提示:
clipboard.png
咱們上面寫的註釋,寫js的時候還能夠提示。

有時候同一個函數有若干種寫法:

clipboard.png

get(1234)
get("zhangsan",18)

那麼d.ts對應的寫法:

declare function get(id: string | number): string
declare function get(name:string,age:number): string

若是有些參數無關緊要,能夠加個?表示非必須。

declare function render(callback?:()=>void): string

js中調用的時候,回調傳不傳均可以:

render()

render(function () {
    alert('finish.')
})

用interface 聲明函數

也能夠用interface去聲明函數類型:

clipboard.png

//Get是一種類型
declare interface Get{
    (id: string): string
    (name:string,age:number):string
}

//get是Get類型的
declare var get:Get

用起來長這個樣子:
clipboard.png

class

固然除了變量和函數外,咱們還有類(class)。

declare class Person {

    static maxAge: number //靜態變量
    static getMaxAge(): number //靜態方法

    constructor(name: string, age: number)  //構造函數
    getName(id: number): string 
}

constructor表示的是構造方法:

clipboard.png

clipboard.png

其中static表示靜態的意思,用來表示靜態變量和靜態方法:

clipboard.png

clipboard.png

對象

declare namespace OOO{
    
}

固然了這個對象上面可能有變量,可能有函數可能有類。

declare namespace OOO{
    var aaa: number | string
    function getName(id: number | string): string
    class Person {

        static maxAge: number //靜態變量
        static getMaxAge(): number //靜態方法

        constructor(name: string, age: number) //構造函數
        getName(id: number): string //實例方法
    }
}

其實就是把上面的那些寫法放到這個namespace包起來的大括號裏面,注意括號裏面就不須要declare關鍵字了。
效果:

clipboard.png

clipboard.png

clipboard.png

對象裏面套對象也是能夠的:

declare namespace OOO{
    var aaa: number | string
    // ...
    namespace O2{
        let b:number
    }
}

效果:

clipboard.png

混合類型

有時候有些值既是函數又是class又是對象的複雜對象。好比咱們經常使用的jquery有各類用法:

new $()
$.ajax()
$()

既是函數又是對象

declare function $2(s:string): void

declare namespace $2{
    let aaa:number
}

效果:

做爲函數用:
clipboard.png

做爲對象用:
clipboard.png

也就是ts會自動把同名的namespace和function合併到一塊兒。

既是函數,又是類(能夠new出來),又是對象

// 實例方法 
interface People{
    name: string
    age: number
    getName(): string
    getAge():number
}
interface People_Static{
    /** 構造函數 */
    new (name: string, age: number): People
    new (id:number): People
    
    /** 做爲對象,調用對象上的方法或者變量 */
    staticA():number
    aaa:string
    
    /** 做爲函數使用 */
    (w:number):number
    (w:string):number
}
declare var People:People_Static

ts3.6增長了新功能,function聲明和class聲明能夠合併了,因此又有了新的寫法:

/** 做爲函數使用 */
declare function People(w: number): number
declare function People(w: string): number

declare class People {
    /** 構造函數 */
    constructor(name: string, age: number)
    constructor(id: number)

    // 實例屬性和實例方法
    name: string
    age: number
    getName(): string
    getAge(): number

    /** 做爲對象,調用對象上的方法或者變量 */
    static staticA(): number
    static aaa: string
}

/** 做爲對象,調用對象上的方法或者變量 */
declare namespace People {
    export var abc: number
}

函數用function,類用class聲明,複雜對象就用namespace,這樣的對應關係簡潔明瞭。

效果:

做爲函數使用:
clipboard.png

類的靜態方法:
clipboard.png

類的構造函數:
clipboard.png
類的實例方法:
clipboard.png

模塊化的全局變量

這個是怎麼回事呢,就是有時候咱們定義全局變量的時候須要引入(別人寫的)文件,好比這樣的,我想聲明個全局變量req:

clipboard.png

因爲咱們當前的d.ts文件使用了import/export語法,那麼ts編譯器就不把咱們經過declare var xxx:yyy當成了全局變量了,那麼咱們就須要經過如下的方式聲明全局變量:

import { Request,Response} from 'express'

declare global {
    var req: Request
    var res: Response

    namespace OOO {
        var a:number
    }
}

用起來長這個樣子:

clipboard.png
其餘類型(number、string blabla)就不一一舉例了,參照上面的例子去掉declare填到global的大括號下就好了。

模塊化(CommonJS)

除了上面的全局的方式,咱們有時候仍是經過require的方式引入模塊化的代碼。

好比這樣的效果:

clipboard.png

對應的寫法是這樣的:

declare module "abcde" {
    export let a: number
    export function b(): number
    export namespace c{
        let cd: string
    }
 }

其實就是外面套了一層 module "xxx",裏面的寫法和以前其實差很少,把declare換成了export

此外,有時候咱們導出去的是一個函數自己,好比這樣的:

clipboard.png

對應的寫法很簡單,長這個樣子:

declare module "app" {
    function aaa(some:number):number
     export=aaa
 }

以此類推,導出一個變量或常量的話這麼寫:

declare module "ccc" {
    const c:400
     export=c
 }

效果:

clipboard.png

ES6的模塊化方式(import export)

declare var aaa: 1
declare var bbb: 2
declare var ccc: 3 //由於這個文件裏咱們使用了import或者export語法,因此bbb和ccc在其餘代碼裏不能訪問到,即不是全局變量

export { aaa }

使用:

import { a1, a2 } from "./A"

console.log(a1)
console.log(a2)

那麼對應的A.d.ts文件是這樣寫的:

declare var a1: 1
declare var a2: 2

export { a1,a2 }

固然了也能這樣寫:

export declare var a1: 1
export declare var a2: 2

不過建議以前的第一種寫法,緣由看這裏https://segmentfault.com/a/11...

固然了還有人常常問default導出的寫法:

declare var a1: 1
export default a1

使用的時候固然就是這樣用了:

import a1 from "./A";

console.log(a1)

UMD

有一種代碼,既能夠經過全局變量訪問到,也能夠經過require的方式訪問到。好比咱們最多見的jquery:

clipboard.png
clipboard.png

其實就是按照全局的方式寫d.ts,寫完後在最後加上declare module "xxx"的描述:

declare namespace UUU{
    let a:number
}
 
declare module "UUU" {
    export =UUU
}

效果這樣:

做爲全局變量使用:
clipboard.png

做爲模塊加載使用:
clipboard.png

其餘

有時候咱們擴展了一些內置對象。好比咱們給Date增長了一個format的實例方法:

clipboard.png

對應的d.ts描述文件這樣寫:

interface Date {
    format(f: string): string
}

.d.ts文件放到哪裏

常常有人問寫出來的d.ts文件(A.d.ts)文件放到哪一個目錄裏,若是是模塊化的話那就放到和源碼(A.js)文件同一個目錄下,若是是全局變量的話理論上放到哪裏均可以————固然除非你在tsconfig.json 文件裏面特殊配置過。

相關文章
相關標籤/搜索