1. 程式人生 > >【TypeScript】型別定義檔案(*.d.ts)

【TypeScript】型別定義檔案(*.d.ts)

在 《從 JavaScript 到 TypeScript 系列》 文章我們已經學習了 TypeScript 相關的知識。 TypeScript 的核心在於靜態型別,我們在編寫 TS 的時候會定義很多的型別,但是主流的庫都是 JavaScript 編寫的,並不支援型別系統。那麼如何讓這些第三方庫也可以進行型別推導呢?

這篇文章我們來講解 JavaScript 和 TypeScript 的靜態型別交叉口 —— 型別定義檔案。

型別定義檔案

在 TypeScript 中,我們可以很簡單的,在程式碼編寫中定義型別:

interface IBaseModel {
    say(keys: string[] | null
): object } class User implements IBaseModel { name: string constructor (name: string) { this.name = name } }

但是主流的庫都是 JavaScript 編寫的,TypeScript 身為 JavaScript 的超集,自然需要考慮到如何讓 JS 庫也能定義靜態型別。

TypeScript 經過了一系列的摸索,先後提出了 tsd(已廢棄)、typings(已廢棄),最終在 TypeScript 2.0 的時候重新整理了型別定義,提出了 DefinitelyTyped

DefinitelyTyped 就是讓你把 “型別定義檔案(*.d.ts)”,釋出到 npm 中,配合編輯器(或外掛),就能夠檢測到 JS 庫中的靜態型別。

型別定義檔案的以 .d.ts 結尾,裡面主要用來定義型別。

例如這是 jQuery 的型別定義檔案 中一段程式碼(為了方便理解做了一些改動)

// 定義 jQuery 需要用到的型別名稱空間
declare namespace JQuery {
    // 定義基本使用的型別
    type Selector = string;
    type TypeOrArray<T> = T | T[];
    type htmlString = string;
}

// 定義 jQuery 介面,jquery 是一個 包含 Element 的集合
interface JQuery<TElement extends Node = HTMLElement> extends Iterable<TElement> { length: number; eq(index: number): this; // 過載 add(selector: JQuery.Selector, context: Element): this; add(selector: JQuery.Selector | JQuery.TypeOrArray<Element> | JQuery.htmlString | JQuery): this; children(selector?: JQuery.Selector): this; css(propertyName: string): string; html(): string; } // 對模組 jquery 輸出介面 declare module 'jquery' { // module 中要使用 export = 而不是 export default export = jQuery; }

型別定義

*.d.ts 編寫起來非常簡單,經過 TypeScript 良好的靜態型別系統洗禮過後,語法學習成本非常低。

我們可以使用 type 用來定義型別變數:

// 基本型別
type UserName = string

// 型別賦值
type WebSite = string
type Tsaid = WebSite

可以看到 type 其實可以定義各種格式的型別,也可以和其他型別進行組合。

// 物件
type User = {
    name: string;
    age: number;
    website: WebSite;
}

// 方法
type say = (age: number) => string

// 類
class TaSaid {
    website: string;
    say: (age: number) => string;
}

當然,我們也可以使用 interface 定義我們的複雜型別,在 TS 中我們也可以直接定義 interface

interface Application {
    init(): void
    get(key: string): object
}

interfacetype(或者說 class) 很像。

但是 type 的含義是定義自定義型別,當 TS 提供給你的基礎型別都不滿足的時候,可以使用 type 自由組合出你的新型別,而 interface 應該是對外輸出的介面。

type 不可以被繼承,但 interface 可以:

interface BaseApplication {
    appId: number
}

export interface Application extends BaseApplication {
  init(): void
    get(key: string): object
}

declare

declare 可以建立 *.d.ts 檔案中的變數,declare 只能作用域最外層:

declare var foo: number;
declare function greet(greeting: string): void;

declare namespace tasaid {
    // 這裡不能 declare
    interface blog {
        website: 'http://tasaid.com'
    } 
}

基本上頂層的定義都需要使用 declareclass 也是:

declare class User {
    name: string
}

namespace

為防止型別重複,使用 namespace 用於劃分區域塊,分離重複的型別,頂層的 namespace 需要 declare 輸出到外部環境,子名稱空間不需要 declare

// 名稱空間
declare namespace Models {
    type A = number
    // 子名稱空間
    namespace Config {
        type A = object
        type B = string
    }
}

type C = Models.Config.A

組合定義

上面我們只演示了一些簡單的型別組合,生產環境中會包含許多複雜的型別定義,這時候我們就需要各種組合出強大的型別定義:

動態屬性

有些型別的屬性名是動態而未知的,例如:

{
    '10086': {
        name: '中國移動',
        website: 'http://www.10086.cn',
    },
    '10010': {
        name: '中國聯通',
        website: 'http://www.10010.com',
    },
    '10000': {
        name: '中國電信',
        website: 'http://www.189.cn'
    }
}

我們可以使用動態屬性名來定義型別:

interface ChinaMobile {
    name: string;
    website: string;
}

interface ChinaMobileList {
    // 動態屬性
    [phone: string]: ChinaMobile
}

型別遍歷

當你已知某個類型範圍的時候,可以使用 inkeyof來遍歷型別,例如上面的 ChinaMobile 例子,我們可以使用 in 來約束屬性名必須為三家運營商之一:

type ChinaMobilePhones = '10086' | '10010' | '10000'

interface ChinaMobile {
    name: string;
    website: string;
}

// 只能 type 使用, interface 無法使用
type ChinaMobileList = {
    // 遍歷屬性
    [phone in ChinaMobilePhones]: ChinaMobile
}

我們也可以用 keyof 來約定方法的引數

export type keys = {
    name: string;
    appId: number;
    config: object;
}

class Application {
    // 引數和值約束範圍
    set<T extends keyof keys>(key: T, val: keys[T])
    get<T extends keyof keys>(key: T): keys[T]
}

整合釋出

有兩種主要方式用來發布型別定義檔案到 npm

  1. 與你的 npm 包捆綁在一起(內建型別定義檔案)

前者,安裝完了包之後會自動檢測並識別型別定義檔案。 後者,則需要通過 npm i @types/xxxx 安裝,這就是我們前面所說的 DefinitelyTyped ,用於擴充套件 JS 庫的型別宣告。

內建型別定義檔案

內建型別定義就是把你的型別定義檔案和 npm 包一起釋出,一般來說,型別定義檔案都放在包根目錄的 types 目錄裡,例如 vue

如果你的包有一個主 .js 檔案,需要在 package.json 裡指定主型別定義檔案。

設定 typestypeings 屬性指向捆綁在一起的型別定義檔案。 例如包目錄如下:

├── lib
│   ├── main.js
│   └── main.d.ts # 型別定義檔案
└── package.json
// pageage.json
{
    "name": "demo",
    "author": "demo project",
    "version": "1.0.0",
    "main": "./lib/main.js",
    // 定義主型別定義檔案
    "types": "./lib/main.d.ts"
}

如果主型別定義檔名是 index.d.ts 並且位置在包的根目錄裡,就不需要使用 types 屬性指定了。

├── lib
│   └── main.js
├── index.d.ts # 型別定義檔案
└── package.json

如果你發的包中,package.json 中使用了 files 欄位的話(npm 會根據 files 配置的規則決定釋出哪些檔案),則需要手動把型別定義檔案加入:

// pageage.json
{
    "files": [
        "index.js",
        "*.d.ts"
    ]
}

如果只發二級目錄的話,把型別定義檔案放到對應的二級目錄下即可:

import { default as App } from 'demo/app'

釋出到 @types organizatio

釋出到 @types organizatio 的包表示源包沒有包含型別定義檔案,第三方/或原作者定義好型別定義檔案之後,釋出到 @types 中。例如 @types/express

根據 DefinitelyTyped 的規則,和編輯器(和外掛) 自動檢測靜態型別。

如果想讓你的包釋出為 @types 包,需要提交一個 pull request 到

https://github.com/DefinitelyTyped/DefinitelyTyped

如果你正在使用 TypeScript,而使用了一些 JS 包並沒有對應的型別定義檔案,可以編寫一份然後提交到 @types

贈人玫瑰,手留餘香。

釋出到 @types organizatio 的包可以通過 TypeSearch 搜尋檢索,使用 npm install --save-dev @types/xxxx 安裝:

這裡寫圖片描述

相關推薦

TypeScript型別定義檔案(*.d.ts)

在 《從 JavaScript 到 TypeScript 系列》 文章我們已經學習了 TypeScript 相關的知識。 TypeScript 的核心在於靜態型別,我們在編寫 TS 的時候會定義很多的型別,但是主流的庫都是 JavaScript 編寫的,並不

TypeScript 型別定義檔案(*.d.ts)自動生成工具

在開發ts時,有時會遇到沒有d.ts檔案的庫,同時在老專案遷移到ts專案時也會遇到一些檔案需要自己編寫宣告檔案,但是在需要的宣告檔案比較多的情況,就需要自動生產宣告檔案。用過幾個庫。今天簡單記錄一下。自己怎麼編寫有很多教程和文件,那裡就不介紹了。 1、為整個包新增宣告檔案 使用微軟的dt

TypeScriptTypeScript+Ionic的Component檔案裡(ts檔案)如何建立物件

在Ionic檔案中,有以下幾個步驟: 1.import導包; import {Component} from '@angular/core'; import {IonicPage, NavParams, ToastController, AlertC

Highchart定義儀表盤配置檔案,儀表盤分段及漸變色

highchart配置出儀表盤 chart: { type: 'gauge', plotBackgroundColor: null, plotBackgroundImage: null, plotBorderWi

Java根據檔案流判斷檔案型別

在讀取檔案的時候我們通常會需要判斷檔案的型別,而根據字尾獲取檔案的型別是不太準確的,所以我們需要讀取檔案流。 /** 常用檔案的檔案頭如下:(以前六位為準) JPEG (jpg),檔案頭:FFD8FF PNG (png),檔案頭:89504E47 GIF (gif),檔案頭:474

如何釋出TypeScript的宣告檔案.d.ts

最近為Dynamic Web TWAIN的JavaScript介面編寫了一份.d.ts檔案。這個檔案就像C/C++用.h檔案。好處就是在使用TypeScript開發的時候,可以提供IntelliSense智慧提示。開發者可以直接看到介面的定義。使用TypeSearch可以找到

Android XML佈局檔案中,使用自定義屬性不提示和不生效

在XML檔案中使用首先要宣告 xmlns:toolbar=http://schemas.android.com/apk/res/cn.zzm.toolbar 注意,“toolbar”可以換成其他的任何名字,後面的url地址必須最後一部分必須用上自定義元件的包名。自定義屬性了

C++變數定義在.h標頭檔案導致 multiple definition of 的解決方法和根本原因

說明:出現這個錯誤,請你先檢查重複定義的變數是否是定義在了.h標頭檔案中,如果是,請您耐心的看完這篇文章,他會告訴你錯誤的根本原因。 如果你很著急,不想弄清楚原因,請直接按下面的方法更改: 假設重複定

4定義下拉框

order viewport down jquer pos bottom last png 下拉框 <!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8

Android自己定義組件系列1——自己定義View及ViewGroup

全部 int ++ btn -i pre 剪切 final 界面 View類是ViewGroup的父類,ViewGroup具有View的全部特性。ViewGroup主要用來充當View的容器。將當中的View作為自己孩子,並對其進行管理。當然孩子也能夠是ViewGrou

Android自己定義圓形ImageView(圓形頭像 可指定大小)

代碼實現 err float avi rim war tor pos dsm 近期在仿手Q的UI,這裏面常常要用到的就是圓形頭像,看到 在android中畫圓形圖片的幾種辦法 這篇文章,了解了制作這樣的頭像的原理.只是裏面提供的方法另一個不足的地方就是

BZOJ5101[POI2018]Powód 並查集

cstring sin 多少 合並 div 一次 mes true printf 【BZOJ5101】[POI2018]Powód Description 在地面上有一個水箱,它的俯視圖被劃分成了n行m列個方格,相鄰兩個方格之間有一堵厚度可以忽略不計的

python web框架補充定義web框架

數據大小 路徑 .py 用戶 ipa clr 接受 values 規範 http協議 HTTP簡介 HTTP協議是Hyper Text Transfer Protocol(超文本傳輸協議)的縮寫,是用於從萬維網(WWW:World Wide Web )服務器傳輸超文本到本

flask第二十四篇——模板6定義過濾器

def 定義 lazy .py highlight abs nbsp tps word 請關註孟船長的公眾號:自動化測試實戰 大家想了解其他過濾器可以參考這裏: http://jinja.pocoo.org/docs/dev/templates/#builtin-fil

獲取TypeScript的聲明文件.d.ts

http col 安裝包 target 文件 目錄 tps div color 一、TypeScript的聲明文件就像C/C++用.h文件。當使用TypeScript調用其他已經編寫好的類庫時,可以提供IntelliSense智能提示。 二、使用npm指令來獲取.d.ts

BZOJ1228[SDOI2009]E&D(博弈論)

博弈 pac iostream cst 打表 。。 name ans getch 【BZOJ1228】[SDOI2009]E&D(博弈論) 題面 BZOJ 洛谷 題解 這種打表找規律的題目真的不知道可以說什麽好啊。。。 #include<iostream>

JVMclass類檔案的結構

作為Java程式猿,我們知道,我們寫好的.java 原始碼,最後會被Java編譯器編譯成字尾為.class的檔案,該型別的檔案是由位元組組成的檔案,又叫位元組碼檔案。那麼,class位元組碼檔案裡面到底是有什麼呢?它又是怎樣組織的呢?讓我們先來大概瞭解一下他的組成結構吧。  

WXS變數定義保留識別符號

以下字元不能作為變數名稱定義: delete void typeof null undefined NaN Infinity var if else true false require this function arguments return for while

typescript數字轉變為漢字(大寫)

其他語言的都有,記錄一下自己剪下的數字:   /**根據數字獲取漢字*/ public changeToCN(num: number): string { let words = ["零", "一", "二", "三", "四", "五", "六", "七", "八",

typescript簡單公用方法

/**範圍內獲取整數隨機數*/ /**範圍內獲取整數隨機數*/ function getRandomInt(min: number, max: number): number { var Range = max - min; var Rand = Math.random();