javascript技巧

关注公众号 jb51net

关闭
首页 > 网络编程 > JavaScript > javascript技巧 > Typescript类型声明文件

详解如何编写一个Typescript的类型声明文件

作者:小p

我们知道TypeScript根据类型声明进行类型检查,但有些情况可能没有类型声明,这个时候就需要我们自己写一个,下面小编就来和大家聊聊如果写一个Typescript的类型声明文件呢

现在有这样一个任务:给一个用 javascript 包写一个类型文件。

这个包导出了一个函数calculator,它具有如下功能:

calculator.js文件

// operator: 只能是 plus | minus
function calculator(operator, numbers) {
  console.log(operator, numbers)
  return
}
calculator.plus = (numbers) => {
  return numbers
}
calculator.minus = (numbers) => {
  return numbers
}
export default calculator

先分析下calculator的结构。

它首先是一个函数,这个函数传递两个参数,第一个参数只能是plusminus,第二个参数是一个数字数组。

其次,它有两个属性,分别是plusminus,参数都是一个数字数组。

下面就来一步步完善这个类型文件。

第一步,创建一个 calculator.d.ts 文件。因为 calculator 本身是一个函数,可以先定义一个函数类型:

calculator.d.ts文件

type IOperator = 'plus' | 'minus'
type ICalculate = (operator: IOperator, numbers: number[]) => number
declare const calculator: ICalculate
export default calculator

配置tsconfig.json

"files": ["calculator.d.ts"]

index.ts文件

可以看到,我们写的类型声明文件生效了。

注意,这里在index.ts引入calculator.js的函数时,calculator.d.ts文件中也一定要加上export default calculator,否则会报错,报calculator.d.ts不是一个模块。

但当我们访问这个函数的属性时,会报错:

这是因为我们只声明它是一个函数,calculator 还有两个属性方法,那怎么办呢?使用 interface:

interface Icalculator {
  (operator: Operator, numbers: number[]): number
  plus(numbers: number[]): number
  minus(numbers: number[]): number
}

这样就大功告成了,最后把这个声明文件提交到@types组织,然后通过npm install @types/calculator下载,这样 typescript 会自动读取类似声明文件。

注意:提交到@types时,类型文件的命名一定是index.d.ts

同时,我们的引入方式就变成了import calculator from 'calculator'

下面让我们来看一个axios库类型定义文件是怎么写的。下面对axios类型声明文件进行精简,保留了重要部分。

// 定义请求头的格式,即 key 只能是字符串,value 是一个联合类型 string | number | boolean
export type AxiosRequestHeaders = Record<string, string | number | boolean>;
// 定义了响应头的格式,即 key 和 value只能是字符串,同时利用 &(交叉类型) 把多个类型合并成一个类型
export type AxiosResponseHeaders = Record<string, string> & {
  "set-cookie"?: string[]
};
// 对请求的参数进行转换,此处对应的就是转换函数
export interface AxiosRequestTransformer {
  (data: any, headers?: AxiosRequestHeaders): any;
}
// 定义了所有请求方法的类型
export type Method =
  | 'get' | 'GET'
  | 'delete' | 'DELETE'
  | 'head' | 'HEAD'
  ...
// 定义了所有返回数据的类型,可以是二进制,也可以是json对象
export type ResponseType =
  | 'arraybuffer'
  | 'blob'
  | 'document'
  | 'json'
  ...
// 请求配置AxiosRequestConfig是一个接口,接口传入了一个泛型,这个泛型就可以流入到里面的属性或值里面。
export interface AxiosRequestConfig<D = any> {
  url?: string;
  method?: Method | string;
  baseURL?: string;
  headers?: AxiosRequestHeaders;
  params?: any;
  data?: D;
  responseType?: ResponseType;
  ...
}
// 请求返回的数据类型,定义了一个interface,里面有data,status等,同时传入了一个泛型,这个泛型可以流入到data里面,这样我就定义了data的类型
export interface AxiosResponse<T = any, D = any>  {
  data: T;
  status: number;
  statusText: string;
  headers: AxiosResponseHeaders;
  config: AxiosRequestConfig<D>;
  request?: any;
}
// 定义了一个Axios的类,这个类定义了构造函数constructor,拦截器interceptors,以及一些调用方法get/post等
export class Axios {
  constructor(config?: AxiosRequestConfig);
  defaults: AxiosDefaults;
  interceptors: {
    request: AxiosInterceptorManager<AxiosRequestConfig>;
    response: AxiosInterceptorManager<AxiosResponse>;
  };
  get<T = any, R = AxiosResponse<T>, D = any>(url: string, config?: AxiosRequestConfig<D>): Promise<R>;
  post<T = any, R = AxiosResponse<T>, D = any>(url: string, data?: D, config?: AxiosRequestConfig<D>): Promise<R>;
  ...
}
// AxiosPromise 继承于 Promise<AxiosResponse<T>>,Promise<AxiosResponse<T>>里面传入了泛型,这样泛型流入到AxiosResponse里面
export interface AxiosPromise<T = any> extends Promise<AxiosResponse<T>> {
}
// 定义了一个Axios实例的接口
export interface AxiosInstance extends Axios {
  (config: AxiosRequestConfig): AxiosPromise;
  (url: string, config?: AxiosRequestConfig): AxiosPromise;
}
export interface AxiosStatic extends AxiosInstance {
  create(config?: AxiosRequestConfig): AxiosInstance;
  Axios: typeof Axios;
  ...
}
declare const axios: AxiosStatic;
export default axios;

首先我们引入import axios from 'axios',这个 axios 的类型就是 AxiosStatic,这个类型上有个 create 的方法:

export interface AxiosStatic extends AxiosInstance {
  create(config?: AxiosRequestConfig): AxiosInstance;
  Axios: typeof Axios;
  ...
}

执行 create 方法后,返回一个类型为 AxiosInstance 的变量:

export interface AxiosInstance extends Axios {
  (config: AxiosRequestConfig): AxiosPromise;
  (url: string, config?: AxiosRequestConfig): AxiosPromise;
}

这个变量首先是一个函数,这个函数可以这么使用(config: AxiosRequestConfig): AxiosPromise;,也可以这么使用(url: string, config?: AxiosRequestConfig): AxiosPromise;,同时它也继承了Axios类型,Axios类型有get, post等方法,所以它就有了如下使用方法:

import axios from 'axios'
const axiosInstance = axios.create()
// 发送请求的三种方式
axiosInstance({ url: 'test.url'})
axiosInstance(url: 'test.url', config: { method: 'get' })
axiosInstance.get('test.url')

到此这篇关于详解如何编写一个Typescript的类型声明文件的文章就介绍到这了,更多相关Typescript类型声明文件内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文