TS的声明文件

2,247 阅读3分钟

声明文件

声明文件就是指xx.d.ts这个文件

全局声明

如果代码作为第三方库发布出去,其他人使用CDN的形式引入这个代码库,就像用<script src="https://cdn.bootcdn.net/ajax/libs/jquery/3.6.0/jquery.js"></script>来引入JQuery,这样编译器是不知道包里的函数类等变量的类型的信息的,这时候就需要声明文件让编译器知道这个包里的类型信息。

声明文件中用declare 或 export来声明一个数据类型或接口

declare const jQuery: (selector: string) => any;
// 或者
declare function JQuery(selector: string): any;

现在我即使没有引入jQuery,仍然能在工作区中获得代码提示

现在模块化开发的情况下这种用法不常用,一般是下面的用法

也可以同样方式抛出全局类型,在模块化下全局变量只能用(window as any).xxx来显式挂载,但是类型能直接抛出

declare type Nullable<T> = T | null;

这样能直接全局使用这个别名

模块声明

在模块化下,需要使用moduel关键字来声明模块

// d.ts文件
declare module "test" {
    export interface Obj {
        a: number;
    }
    export default interface OObj {
        b: number;
    }
}
// ts文件
import type OObj from "test"; // 这里就像是从一个文件中引入的
import type { Obj } from "test";
let obj: Obj = { a: 1 };
let oobj: OObj = { b: 2 };

模块中的类型也能被覆盖、继承

// 另一个d.ts文件
declare module "test" {
    export interface ABC {
        c: number;
    }
    export interface ABC extends Obj {}
}
// ts文件
import type { ABC } from "test";
let abc: ABC = { a: 1, c: 2 };

但是如果是node_modules中的模块,声明模块会覆盖它,得在重新声明模块之前用副作用导入它

不过挂载vue全局属性或者修改vue-router的meta属性的时候也是这样,但不需要引入,没搞懂

手动试试

你可以在node_modules文件夹下新建一个文件夹,我这里就叫test了,放入以下文件

// package.json
{
    "main": "./index.js",
    "types": "./index.d.ts" // 如果就是index是可以不声明的
}
// index.js
export function A(arg) {
    return arg
}

export function B(arg) {
    return arg + " from B"
}
// index.d.ts
export interface AType {
    (arg: number): number
}
export const A: AType

在导入函数A时会有语法提示并且能导入A的类型,但是导入B时会报错

import { A } from "test" // OK
import type { AType } from "test" // OK
import { B } from "test" // ERROR

这时能在项目中声明它

// test.d.ts
import "test";

declare module "test" {
    export function B(arg: number): string;
}

这样用B的时候就不会报错了

在ts文件中声明全局模块

使用declare global{ }来声明

一些题外话,为什么在用脚手架搭建的框架项目中能直接引用css等文件?这是因为它们都内置了一些类似declare module "*.css" { ... }这样的模块,这样ts就会以为你引入的是模块而不是文件

在vue项目中就有有类似的代码用来声明*.vue文件的导入类型

打个广告,我的个人博客终于上线了(虽然还没logo),因为最近学ts更新比较频繁,有兴趣可以来看看