ts实战:给没有类型声明的第三方库编写一个类型声明文件
前情提要
在github找了一个原生代码写的Toast库,安装后发现没有ts类型声明,通过安装@types/库名
也没有现成的对应的类型声明库,于是想着自己写一份声明文件用,也是第一次,所以找了好些教程,这里做个笔记。
npm仓库: Toastify
说实话这个库不太行,不支持多个toast,权当练手了。
类型声明文件
在项目中,比如我是在src目录下创建一个types目录,专门存放这些类型声明文件,创建一个名为Toastify.d.ts
的文件。
内容如下:
declare module "toastify" {
/** toast定位 */
export type ToastifyPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
/** 延迟 */
export type ToastifyDelay = number;
/** 速度 */
export type ToastifySpeed = number;
/** 插入的节点id选择器 */
export type ToastifyNode = string;
/** 配置参数 */
export interface ToastifyOptions {
/** 定位 */
position: ToastifyPosition;
/** 延迟 */
delay: ToastifyDelay;
/** 速度 */
speed: ToastifySpeed;
/** 插入的节点id选择器 */
element: ToastifyNode;
}
/** toast标题 */
export type ToastifyTitle = string;
/** toast内容 */
export type ToastifyBody = string | void | null;
export class Toastify {
private options: ToastifyOptions = {
position: "bottom-right",
delay: 5000,
speed: 10,
element: "body",
};
public default(title: ToastifyTitle, body: ToastifyBody): void;
public info(title: ToastifyTitle, body: ToastifyBody): void;
public success(title: ToastifyTitle, body: ToastifyBody): void;
public error(title: ToastifyTitle, body: ToastifyBody): void;
public warning(title: ToastifyTitle, body: ToastifyBody): void;
public setOption<K extends keyof ToastifyOptions>(type: K, value: ToastifyOptions[K]): void;
}
const toastify = new Toastify();
export default toastify;
}
先通过declare module
的方式,声明一个扩展类型声明,因为我们的库原本就没有声明,所以不必担心在全局声明下自定义的扩展声明会覆盖原有的类型定义。
如果是库已经有定义了,可以通过interface等手段,但是这个不是我们本次重点,可以自行搜索相关解决方法。
根据查看源码所得,默认导出的是一个实例对象,export导出的是类。
其中类对外抛出了几个方法,其中setOption
比较特殊,它的key必须是ToastifyOptions
中所声明的key,所以我通过keyof的方式定义它的key,但是value又必须和key对应的值类型相同,所以通过泛型的方式,将K
定义成继承keyof ToastifyOptions
。
然后在value的类型上通过ToastifyOptions[K]
定义类型,ts就能自动推断正确的类型了。
一开始我为了和库的类相同,我也声明了一个默认options,但是想了一下,发现其实没必要,因为我是类型声明,所以声明类型就行了,于是最终改成这样:
declare module "toastify" {
/** toast定位 */
export type ToastifyPosition = "top-left" | "top-right" | "bottom-left" | "bottom-right";
/** 延迟 */
export type ToastifyDelay = number;
/** 速度 */
export type ToastifySpeed = number;
/** 插入的节点id选择器 */
export type ToastifyNode = string;
/** 配置参数 */
export interface ToastifyOptions {
/** 定位 */
position: ToastifyPosition;
/** 延迟 */
delay: ToastifyDelay;
/** 速度 */
speed: ToastifySpeed;
/** 插入的节点id选择器 */
element: ToastifyNode;
}
/** toast标题 */
export type ToastifyTitle = string;
/** toast内容 */
export type ToastifyBody = string | void | null;
export class Toastify {
private options: ToastifyOptions;
public default(title: ToastifyTitle, body: ToastifyBody): void;
public info(title: ToastifyTitle, body: ToastifyBody): void;
public success(title: ToastifyTitle, body: ToastifyBody): void;
public error(title: ToastifyTitle, body: ToastifyBody): void;
public warning(title: ToastifyTitle, body: ToastifyBody): void;
public setOption<K extends keyof ToastifyOptions>(type: K, value: ToastifyOptions[K]): void;
}
const toastify = new Toastify();
export default toastify;
}
又省了几行代码!
由于.d.ts是不需要自动引入的,ts会自动获取这些文件,所以写完就没啥问题了,import引入也不会报错了。
import Toastify from "toastify";
import "toastify/dist/toastify.css";
Toastify.setOption("delay", 9999);
Toastify.setOption("element", "sss");
Toastify.error("请求超时", null);
类型推断也非常美好,又学到了新的知识。
本文系作者 @木灵鱼儿 原创发布在木灵鱼儿站点。未经许可,禁止转载。
暂无评论数据