例举Typescript声明文件写法

刚开始写声明文件时,不知道如何下手。但是,随着反复的实验,以及参考一些公开的声明文件,发现写声明文件也不是那么难。只要熟悉Typescript,了解Typescriptjavascript之间的异同,很容易就能够根据API写出对应的声明文件来

9d4d63ea98cc7106c3a5f18a8c70742b.png

声明文件是以.d.ts为后缀的文件,文件名称与javascript文件名称一致。声明文件主要是解决js文件在Typescript中的使用问题,有了声明文件,编译器就可以对引入的js库做类型检查,同时支持代码智能提示。

下面,就通过例子来讲解声明文件是如何编写的吧。

例1:关于方法的定义

API:
getAccount(id)
getInfo()

声明:

declare getAccount(id: number):void
declare getInfo():any

方法只要在方法前加入declare即可暴露该方法。其次,如果方法有返回参数,可使用any,如果没有,可使用void,不写即为any,如果知道具体的类型,也可以填具体的类型。

例2:关于类型

2-1: 简单声明

常用的基本类型有 元组、数组、string、number、boolean,另外还有枚举

API:
getName()

输出:
"somenone"

声明:

declare getName():string
//或
declare getName():any

2-2:多种类型

API:
getExtraData(id)

输出:
"somenone"
或者
1
或者
undefine

声明:

declare getExtraData(id:number): string|number|undefine
//或
declare getExtraData(id:number):any
//或
declare getExtraData(id:any):any

如果参数非必须,则可以这样定义

declare getExtraData(id?:number): string|number|undefine

任何类型都可以使用any替代,如果不知道是什么类型,或者不关心返回类型,或者返回类型太复杂,类型不止一种,这时候,通常用any替代是一个比较省事的方法。

当然,最好是越详细越好,这样可以方便编译器做类型检查以及代码提示,从而规范自己的代码

接下来的例子,类型同样可以使用any替代

2-3: 返回数据或参数为json对象

一般在声明文件中,返回的json数据可以单独定义成类型,基本类型也可以取别名。

declare type Name=string;
declare type  Info = {
  name: string
}

举例:

API:
# 方法
getAccount(id)
# 输出

{
  "name":"someone",
  "age":12,
  "gender":true,
  "extra":{
    "loginTome": 1
  }
}

声明:

declare type Result = {
  name: string,
  age: string,
  gender: boolean,
  extra: any
}
declare getAccount(id:number): Result

同样Result可以写成这样:

declare type ResultItem = {
  loginTome: number
}
declare type Result = {
  name: string,
  age: number,
  gender: boolean,
  extra: ResultItem
}

如果图省事,可以这样定义:

declare type Result = {
  name: string,
  age: number,
  gender: boolean,
  extra:{
    loginTome: number
  }
}

也可以使用interface来定义:

declare interface Result{
  name: string,
  age: number,
  gender: boolean,
  extra:{
    loginTome: number
  }
}

对于一些非必需的参数可以使用?,一些多类型的参数,可以使用|.

?<Type> = <Type>|undefine

declare type Result = {
  name: string,
  age: number,
  gender: boolean,
  extra?: {
    loginTome: number
  }
}

// 或

declare type Result = {
  name: string,
  age: number,
  gender: boolean,
  extra : {
    loginTome: number
  }|undefine
}

由上述可以找到,声明文件的定义可以根据每个人的需求去定义,并不需要完全一致。甚至,如果方法太多,一些用不到的方法可以不声明。

同理,参数为json也是一样这样定义类型

例3:关于类

一般类使用class或者interface定义,如果类中有静态方法 —— 即无须实例化对象即可使用的属性和方法,则需要将这些方法写到namespace

其中声明文件最主要的一部分,就是类的声明。

例3-1:基本的类

var a = new Account(1);
console.log(a.name)
console.log(a.getExtra())
console.log(Account.TypeOfUser)
Account.login(a.id)
输出:

"someone"
"{
  "loginTime": 1
}"
"USER"

声明:

declare class Account{
  constructor(id: number);
  getExtra(): Account.ExtraData
  name:string
  id: number
}

declare namespace Account{
  interface ExtraData{
    loginTime: number
  }
  const TypeOfUser:string
  function login(id:number):any
}

解析:

这里的ExtraData名字可以随意取,不要重名即可,也不一定放在Account的命名空间中,但是一般都放在命名空间中,这样就不会引起过多的全局变量,同时大大的减少重名的变量

例3-2 如果例3-1中的new去掉,该如何声明呢?

var a = Account(1);
console.log(a.name)
...
declare function Account(id: number): Account;
declare interface Account {
    getExtra(): Account.ExtraData
    name: string
    id: number
}

declare namespace Account {
    interface ExtraData {
        loginTime: number
    }
    const TypeOfUser: string
    function login(id: number): any
}

例4: 方法的“重载”

声明文件允许出现多个相同名称的方法,在类和接口里面同样是允许这样做的

declare getExtraData(id?:number): any

那么前面提到的getExtraData可以有新的写法

declare getExtraData(id:number): any
declare getExtraData(): any

这样,就可以很方便的区分可以传递不同数量参数的方法的情况

例5: 关于继承

API:

getData(1)
getResult(1)

输出:
// getData
{
  "id":1,
  "time": 0,
  "errCode": 0,
  "res":{
    "name":"someone"
  }
}

// getResult
{
  "id":1,
  "time": 0,
  "errCode": 0,
  "res":{
    "age": 1
  }
}

例2-3一样,可以分别定义一个类型:

declare interface Data {
  id: number,
  time: number,
  errCode: number,
  res:{
    name: string
  }
}

declare interface Result {
  id: number,
  time: number,
  errCode: number,
  res:{
    age: number
  }
}

但是这样,显然不是很好,因为可以看出来,DataResult有很多相似的地方,所以应该是可以优化的,下面我就来介绍一下几种优化方法

方法1:一劳永逸的方法

把变化的部分类型定义为any,这样的话无论res如何变化,同一类型都可以用Base来作为返回结果(也可以是方法参数)的类型

declare interface  Base {
  id: number,
  time: number,
  errCode: number,
  res: any
}

方法2:兼容模式

使用|,可以不断的添加新的类型,不过在使用上会带来诸多不便,不建议使用

declare interface  DataItem{
    name: string
}

declare interface  ResultItem{
    age: number
}

declare interface  Base {
  id: number,
  time: number,
  errCode: number,
  res: DataItem|ResultItem
}

方法3:兼容模式2

res内把所有可能的参数都加上,如果所有情况都出现,则无需加?,否则就要加?。这种方式也不太建议使用,不过在某些场合还是可以用到的。比如res中也有很多相同的字段,或者大部分都差不多。使用的时候带?的,需要判断是否为undefine

declare interface  Base {
  id: number,
  time: number,
  errCode: number,
  res: {
    name?: string
    age?: number
  }
}

方法4:继承

这种方式感觉好像还麻烦了些,不过却是一个好的结构,没有出现重复的代码,也就意味着出现错误的几率会变小,同时类型越多,这种写法的优势就越明显,还是有一定的借鉴价值的。

interface  Base {
  id: number,
  time: number,
  errCode: number
}

interface  DataItem{
    name: string
}

interface  ResultItem{
    age: number
}

declare interface Data extends Base {
  res: DataItem
}

declare interface Result extends Base {
  res: ResultItem
}

方法5:继承 + 泛型

其中Item可以写上相同的属性,也可以是空接口。

利用泛型后,等于进一步优化了方法4res是相同类型的都有的属性,但是其中结构又各有差异,所以用泛型是最好的选择。这个也是比较推荐的一种写法。

interface Item { }

interface Base<T extends Item> {
  id: number,
  time: number,
  errCode: number,
  res: Item
}

interface  DataItem extends Item{
    name: string
}

interface  ResultItem extends Item{
    age: number
}

declare interface Data extends Base<DataItem> {}
declare interface Result extends Base<ResultItem> {}

总结

写了这么多,可以知道,其实声明文件编写并不是那么严格,但是一个好的声明文件还是要越详细越好。如果是个人使用,方法和属性太多太杂的话,就可以考虑忽略掉那些不会用到的方法和属性,毕竟没必要花太多时间来编写声明文件。如果用到了,在添加上对应的声明即可。

同时,声明文件的编写,可以充分利用Typescript的特性,也要熟悉javascript的语法,这样就可以将js库的接口很好的对接上ts了。

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 213,711评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,079评论 3 387
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 159,194评论 0 349
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,089评论 1 286
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,197评论 6 385
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,306评论 1 292
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,338评论 3 412
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,119评论 0 269
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,541评论 1 306
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,846评论 2 328
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,014评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,694评论 4 337
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,322评论 3 318
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,026评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,257评论 1 267
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,863评论 2 365
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,895评论 2 351

推荐阅读更多精彩内容