例举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
  }
}

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

? = |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 {
  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 {}
declare interface Result extends Base {}

总结

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

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

你可能感兴趣的:(例举Typescript声明文件写法)